JVM探究
- 请你谈谈对JVM的理解? Java8虚拟机和之前的变化更新?
- 什么是OOM, 什么是栈溢出?怎么分析?
- JVM的常用调优参数有哪些?
- 内存快照如何抓取, 怎么分析Dump文件?
- 谈谈JVM中, 类加载器的认识?
JVM的位置
JVM的体系结构
所谓的JVM调优, 99%的情况下都是在方法区和堆中调的. 这之中绝大部分都是在调堆.
运行时数据区中的 栈, 本地方法栈, 程序计数器这三个部分不可能有垃圾
类加载器
加载Class文件: new Student();
引用是在栈里, 具体的实例放在堆中
实例化一个Car类的过程:
生成的实例对象包括各种属性放在堆中, 名字也就是地址放在栈中. 引用时根据栈中的地址去堆中引用
1 | public class Car { |
输出结果为:
1 | class Car |
类加载器的分类:
- 虚拟机自带的加载器
- 启动类(根)加载器: 负责加载%JAVA_HOME%\bin目录下的所有jar包,或者是-Xbootclasspath参数指定的路径;
- 扩展类加载器: 负责加载%JAVA_HOME%\bin\ext目录下的所有jar包,或者是java.ext.dirs参数指定的路径;
- 应用程序加载器: 负责加载用户类路径上所指定的类库,如果应用程序中没有自定义加载器,那么次加载器就为默认加载器。
1 | public class Car { |
输出为:
1 | jdk.internal.loader.ClassLoaders$AppClassLoader@3fee733d |
双亲委派机制
- 类加载器收到类加载的请求
- 将这个请求向上委托给父类加载器去完成, 一直向上委托, 直到启动类加载器
- 启动类加载器检查是否能够加载当前这个类, 能加载就结束, 使用当前加载器, 否则, 抛出异常, 通知子加载器进行加载
接下来举个例子:
大家所熟知的Object类,直接告诉大家,Object默认情况下是启动类加载器进行加载的。假设我也自定义一个Object,并且制定加载器为自定义加载器。现在你会发现自定义的Object可以正常编译,但是永远无法被加载运行。
这是因为申请自定义Object加载时,总是启动类加载器,而不是自定义加载器,也不会是其他的加载器。
沙箱安全机制
Java安全模型的核心就是Java沙箱, 沙箱是一个限制程序运行的环境. 沙箱机制就是将Java代码限定在虚拟机特定的运行范围中, 并且严格限制代码对本地系统资源访问, 通过这样的措施来保证对代码的有效隔离, 防止对本地系统造成破坏. 沙箱主要 限制系统的资源访问 , CPU, 内存, 文件系统, 网络. 不同级别的沙箱对这些资源访问的限制也可以不一样
Native
在Java 的Thread
类中, 有这样的方法:
凡是带了native
关键字的, 说明java的作用范围达不到了, 会去调用底层c语言的库
会进入本地方法栈, 然后它会调用JNI(本地方法接口), 继而调用本地方法库
JNI的作用: 扩展Java的使用, 融合不同的编程语言为Java所用
PC寄存器
程序计数器: Program Counter Register
每个线程都有一个程序计数器, 是线程私有的, 就是一个指针, 指向方法区中的方法字节码(用来存储指向一条指令的地址, 也即将要执行的指令代码), 在执行引擎读取下一条指令, 是一个非常小的内存空间, 几乎可以忽略不计.
方法区
方法区是被所有线程共享, 所有字段和方法字节码, 以及一些特殊方法, 如构造函数, 接口代码也在此定义, 简单说, 所有定义的方法的信息都保存在该区域, 该区域属于共享区间;
静态变量, 常量, 类信息(构造方法, 接口定义), 运行时的常量池存在方法区中, 但是实例变量存在堆内存中, 和方法区无关.
栈
栈内存, 主管程序的运行, 生命周期和线程同步
线程结束, 栈内存也就释放, 对于栈来说, 不存在垃圾回收问题
一旦线程结束, 栈就Over
存放: 8大基本类型 + 对象引用 + 实例的方法
对象的实例化过程视频解析:
https://www.bilibili.com/video/BV1HE411E7kY?from=search&seid=7388971973574996958
三种JVM
- Sun公司: HotSpot
- BEA: JRockit
- IBM: J9VM
堆
Heap, 一个JVM只有一个堆内存, 堆内存的大小是可以调节的.
类加载器读取了类文件后, 一般会把什么东西放到堆中? 类, 方法, 常量, 变量
堆内存中还要细分为三个区域:
- 新生区(伊甸园区)
- 养老区
- 永久区
新生区
类诞生, 成长的地方, 甚至死亡
伊甸园区, 所有的对象都是在 伊甸园 区
永久区
这个区域常驻内存的, 用来存放JDK自身携带的Class对象, Interface元数据, 存储的是Java运行时的一些环境或类信息
- 1.6之前 : 永久代, 常量池实在方法区
- 1.7: 永久代, 但是慢慢退化了, “去永久代”, 常量池在堆中
- 1.8之后 : 无永久代, 常量池在元空间
默认情况下, JVM分配的总内存是电脑内存的1/4, 而初始化的内存为: 1/64
- JVM的体系结构
- 类加载器
- 双亲委派机制
- 沙箱安全机制
- Native
- PC寄存器
- 方法区
- 栈
- 三种JVM
- 堆
- 新生区
- 老年区
- 永久区
- 堆内存调优
- GC
- 常用算法
- JMM
- 总结
- 百度
- 思维导图