JVM面试
2021-10-18 09:42:28 0 举报
AI智能生成
2021 年秋招常见 JVM 知识
作者其他创作
大纲/内容
垃圾收集
标记算法
可达性分析
引用
1. 强引用:不回收
2. 软引用:内存不足则回收
3. 弱引用:发现即回收
4. 虚引用:对象跟踪回收,无法通过虚引用获取对象
2. 软引用:内存不足则回收
3. 弱引用:发现即回收
4. 虚引用:对象跟踪回收,无法通过虚引用获取对象
gc root
1. 虚拟机栈中的对象
2. static 修饰对象
3. 本地方法栈中引用的对象
4. final 修饰的对象
2. static 修饰对象
3. 本地方法栈中引用的对象
4. final 修饰的对象
回收算法
复制
1. 将内存分为两块,回收时,将eden 和 s0 区复制到 s1 中
2. 清除eden 和 s0 区
3. 将 s0 和 s1 互换
2. 清除eden 和 s0 区
3. 将 s0 和 s1 互换
标记清除
1. 从GCRoot 进行搜索,标记存活对象
2. 收集器从内存头到尾遍历,对未标记对象进行清理
2. 收集器从内存头到尾遍历,对未标记对象进行清理
标记整理
1. gc root 进行搜索,标记存活对象
2. 将存活对象移动至内存的一端
3. 清除掉边界外的对象
2. 将存活对象移动至内存的一端
3. 清除掉边界外的对象
垃圾收集器
年轻代收集器
serial
STW 暂停用户线程,单线程收集,只有一个回收线程,使用 复制 算法
parNew
serial 的多线程版本,有多个回收线程,使用 复制 算法
Parallel Scavenge
吞吐量优先,多线程回收, 使用 复制 算法
吞吐量 = 运行代码时间 / (运行用户代码时间 + 垃圾收集时间)
老年代收集器
serial Old
serial的 老年代版本,使用 标记整理 算法
Parallel Old
Parallel 的老年代版本 采用 标记整理 算法
CMS
cms 是Hotspot虚拟机中第一款真正意义上的并发收集器,
实现了垃圾收集线程与用户线程同时工作【使用 标记清除 算法】
1. 初始标记:会stw 搜索 GcRoot 直接关联的对象
2. 并发标记:递归遍历直接关联对象
3. 重新标记:stw 重新标记在并发标记中产生的垃圾
4. 并发清理:并发清理
实现了垃圾收集线程与用户线程同时工作【使用 标记清除 算法】
1. 初始标记:会stw 搜索 GcRoot 直接关联的对象
2. 并发标记:递归遍历直接关联对象
3. 重新标记:stw 重新标记在并发标记中产生的垃圾
4. 并发清理:并发清理
暂停时间优先:单次 stw 时间最短
整堆 收集器
G1
官方给g1设定的目标是 在延迟可控的情况下获得尽可能高的吞吐量
G1 将内存分割为很多不相关的区域(region),使用不同region
来代表 eden、s0\s1、幸存者1区、老年代等;G1 避免在Java堆中
进行全域垃圾收集,g1 跟踪各个 Region 里面的垃圾堆的价值大小
在后台维护一个优先列表,每次根据允许时间,优先回收价值大的region
G1 将内存分割为很多不相关的区域(region),使用不同region
来代表 eden、s0\s1、幸存者1区、老年代等;G1 避免在Java堆中
进行全域垃圾收集,g1 跟踪各个 Region 里面的垃圾堆的价值大小
在后台维护一个优先列表,每次根据允许时间,优先回收价值大的region
关键信息
stw
在GC事件发生过程中,会停止其他用户线程
可达性分析算法中枚举根节点(GC Roots)会导致所有Java执行线程停顿
(分析过程中对象引用关系会导致结果的准确性无法保证)
可达性分析算法中枚举根节点(GC Roots)会导致所有Java执行线程停顿
(分析过程中对象引用关系会导致结果的准确性无法保证)
safe point
程序执行时并非所有地方都能停顿下来开始GC,只有特定位置可以停顿,
这些位置就是 safe point;设置一个中断标志,各个线程运行到 safe point
主动轮询这个标志,如果中断标志为真,则将当前线程中断挂起。
这些位置就是 safe point;设置一个中断标志,各个线程运行到 safe point
主动轮询这个标志,如果中断标志为真,则将当前线程中断挂起。
排查\调优
类加载器
类加载器
引导类加载器
负责加载 rt.jar 即 java javax sun 开头的类
扩展类加载器
负责加载 jre/lib/ext 下的类
应用类加载器
其他类的加载器
自定义类加载器
1. 继承 ClassLoader
2. 重写 findClass() 方法
2. 重写 findClass() 方法
类加载过程
加载
1. 将字节码静态存储结构转化成方法区运行时数据结构
2. 在方法区生成这个类的
2. 在方法区生成这个类的
链接
验证
保证被加载的类文件,满足Java 虚拟机规范
准备
为 static 修饰的变量分配内存,并赋初始值【0、null】
解析
将二进制数据中的符号引用转换为直接引用
符号引用&直接引用
初始化
本质上是 <clinit> 方法的执行,对 static 修饰的变量进行赋值
双亲委派机制
每个类都有对应的加载器,当一个类需要加载时,会向上进行委托,
直到引导类加载器,如果类加载器不负责加载该类,则向下尝试加载
好处是,保证了类只加载一次,且加载的是正确的类【破坏方式,写一个自定义的类加载器】
直到引导类加载器,如果类加载器不负责加载该类,则向下尝试加载
好处是,保证了类只加载一次,且加载的是正确的类【破坏方式,写一个自定义的类加载器】
运行时数据区
线程私有
程序计数器
一块较小的空间,可以看做是当前线程锁执行的字节码行号指示器
字节码解释器通过改变计数器的值选取下一条指令,程序分支、跳转
循环、异常处理、线程切换恢复都需要通过计数器完成。没有OOM的区域
字节码解释器通过改变计数器的值选取下一条指令,程序分支、跳转
循环、异常处理、线程切换恢复都需要通过计数器完成。没有OOM的区域
Java虚拟机栈
单位是栈帧,用于存储局部变量表、操作数栈、动态链接、方法出口等信息
每个方法从调用到执行完成,对应一个栈帧在虚拟机中入栈到出栈的过程
每个方法从调用到执行完成,对应一个栈帧在虚拟机中入栈到出栈的过程
局部变量表
存储方法 参数、方法内变量,定义为一个数字数字,类型包括 基本数据类型、对象引用类型、返回地址类型
单位是 槽 sloat,32位类型占1个、64位类型和引用类型占两个
单位是 槽 sloat,32位类型占1个、64位类型和引用类型占两个
操作数栈
在方法执行过程中,根据字节码指令,进行入栈\出栈的操作
主要用于保存计算过程的中间结果,同时作为计算过程中变量的临时存储空间
主要用于保存计算过程的中间结果,同时作为计算过程中变量的临时存储空间
动态链接
指向运行时常量池的方法引用,例如一个方法调用了其他方法,
就是通过常量池中指向方法的符号引用表示的,
动态链接的作用是将符号引用转换成调用方法的直接引用
就是通过常量池中指向方法的符号引用表示的,
动态链接的作用是将符号引用转换成调用方法的直接引用
方法返回地址
本地方法栈
与Java 虚拟机栈类似,区别在于用于执行 native 方法
本地方法:有时我们编写的程序需要 操作系统、底层硬件的支持
本地方法接口为我们屏蔽了这些的底层实现
本地方法接口为我们屏蔽了这些的底层实现
线程公有
堆
TLAB
Thread Local Allocation Buffer 由于对象实例创建在JVM 中非常频繁,
因此在并发环境下从堆区划分内存空间是不安全的,从内存模型的角度,
对 Eden 进行细分,JVM 为每个线程分配了一个私有缓存区域。虽然不是
所有对象实例都能在TLAB中成功分配,但JVM会将TLAB作为内存分配的
首选,开发人员可以通过 -XX:useTLAB 设置是否开启。
因此在并发环境下从堆区划分内存空间是不安全的,从内存模型的角度,
对 Eden 进行细分,JVM 为每个线程分配了一个私有缓存区域。虽然不是
所有对象实例都能在TLAB中成功分配,但JVM会将TLAB作为内存分配的
首选,开发人员可以通过 -XX:useTLAB 设置是否开启。
分代
由于对象往往是 “朝生夕死的”,根据对象的特点,JVM 将 堆空间分成了两部分,
年轻代、老年代,年轻代发生gc的次数较为频繁,而老年代则较少的发生gc,年轻代
根据所选用的 垃圾收集算法 ,分割成了 eden 区 s0 和 s1 区。
年轻代、老年代,年轻代发生gc的次数较为频繁,而老年代则较少的发生gc,年轻代
根据所选用的 垃圾收集算法 ,分割成了 eden 区 s0 和 s1 区。
方法区
【Hotspot】JDK 7 之前方法区被称为永久代,存放于Java 内存上
JDK 8 称为 元空间,存放于 直接内存
JDK 8 称为 元空间,存放于 直接内存
0 条评论
下一页