JVM面试题总结-精炼版
JVM 体系
整理了JVM 包含的所有面试题。看这一篇就够啦!
一、面试问:聊聊JVM(JVM构成)
大体分为四块:
- 类加载子系统
- 运行时数据区(JVM 内存模型)
- 本地接口
- 程序计数器
1.类加载子系统
也大致分为四部分。
- 类加载过程。
- 类加载器种类。
- 类加载器初始化过程。
- 类加载机制
1.1类加载过程
- 加载:加载class字节码文件到内存中。
- 验证:验证字节码文件正确性。
- 准备:给静态变量分配空间,赋予零值。
- 解析:把常量池中的符号引用转换为直接引用。
- 初始化:对静态变量赋予程序中的初始值,并执行静态代码块。
1.2类加载器种类
- 启动类加载器:加载JRE lib 下的包
- 扩展类加载器:JRE lib/ext 下的包
- 应用类加载器:classpath 下的包
- 自定义加载器:加载用户自定义路径的包
1.3类加载器初始化过程
- 创建JVM 启动器实例对象 Launcher, 单例模式唯一一个。
- Launcher 实例对象的构造方法会创建两个类加载器。(ExtClassLoader和AppClassLoader)
- JVM 默认使用Launcher 中的getLoader()获得的appClassLoader 去加载代码
1.4类加载机制
双亲委派机制
- 描述: 类在加载时,总是会先向上加载,检查父类加载器是否已经加载,如果无父类加载器加载,那么从当前类本身路径加载。
- 优点:
(1) 沙箱安全机制,防止开发者自定义类覆盖了核心库。
(2) 避免重复加载,之会被加载一次。
2.重点:运行时数据区(JVM 内存模型)
大致可分为五部分:
2.1 方法区
存放静态变量 + 常量 + 类信息等。
2.2 程序计数器
记录当前线程执行的行号。
2.3 本地方法栈
为本地方法服务。在执行引擎执行时加载本地方法。
2.4 栈
java 线程执行方法的内存模型,一个线程对应一个栈。 每个方法执行时会创建一个栈帧(用于存放局部变量,方法出口等信息),不存在垃圾回收。 只要线程结束栈就被释放。
2.5 堆
虚拟机启动时根据配置 自动分配创建。用于存放对象实例,当空间不足创建对象时,会抛出OOM(OutOfMemoryError) 异常。 也是GC 管理的主要区域。
分为年轻代和老年代
年轻代(占比 1/3)
类创建的区域 ,分为伊甸区(Eden space)和幸存者区(Survivor space),一般情况所有的类都是在伊甸区被new出来的。幸存区又分为From(S0)和To(S1)区。当Eden区的空间用完时,会触发minor GC, 将没有被引用的对象进行销毁,然后将Eden 区剩余对象 转移到 幸存者区的From 区,如果满了,再次触发 GC,然后移动到TO 区。 每次对象年龄会加一。
- Eden 伊甸区 (占比年轻代的8/10)
- Survivor space 幸存者区
(1)From 区(S0区)占比年轻代的1/10。
(2)To 区(S1区)占比年轻代的1/10。
老年代(占比 2/3)
- 定义:年轻代里经过多次GC依然存活的对象会被移到老年代区(大于15),或者对象太大也会直接放入老年代区。如果满了,将发生Full GC, 如果GC 后,依然空间不足,那么会抛出OOM.
- STW事件:full GC发生时,会出现整个应用程序的停顿。
元空间
在JDK1.8之后,元空间替代了永久代,它是对JVM规范中方法区的实现,区别在于元数 据区不在虚拟机当中,而是用的本地内存。
3.字节码执行引擎
执行字节码指令
3.Native Interface(本地接口)
与本地交互,是其它编程语言交互的接口。