JVM面试总结
-
类加载机制
-
装载
全路径、类加载器、寻找类(双亲委派)、
-
链接
验证:文件格式验证、元数据验证、字节码验证、符号引用验证
准备:为类的静态变量分配内存,并将其初始化为默认值,这是
默认值的初始化
,并不是赋值,需要注意解析:将类中的符号引用转换为直接引用(我的理解就是本来是通过变量引用,现在直接把空间地址传给它)
-
初始化
对类的成员变量,静态代码执行初始化操作
-
-
双亲委派模型
往上找父,保证唯一
-
2.1 类加载器类型:
- BootStrap ClassLoader 启动类加载器、跟加载器
- ExtClassLoader 扩展类加载器
- AppClassLoader 应用类加载器
- Customer ClassLoader 自定义类加载器
-
2.2 作用
- 保证JDK核心类的优先加载
-
2.3 如何打破
- 自定义类加载器,重写loadClass方法
- 使用线程上下文类加载器
-
-
运行时数据区
JVM运行时数据区,由此可引申到JMM内存模型
-
内存划分:栈内存、堆内存、方法区、本地方法区、寄存器
-
JVM运行时数据区,方法区和堆内存
堆内存又分为,老年代(Old – Major GC)、新生代(Young – Eden、Survivor(S0、S1))
新生代:S0:S1 = 8:1:1
S0和S1 存在的意义是 虽然浪费了10%的空间,但是避免了空间碎片
当S0或S1存储不了大的对象的时候,存在一个
内存担保机制
,可以向Old借空间,用完了,再还给它 -
垃圾回收算法
- 标记删除
- 空间碎片,内存不连续
- 标记和清除都比较耗时,要扫描两次,效率比较低
- Old
- 标记复制
- 浪费10%的空间
- 空间连续
- Young(Eden、S0、S1)
- 标记整理
- 没有保留区域
- 没有空间碎片
- Old
Full GC = Major GC + Young GC+MetaSpace的GC
- 标记删除
-
垃圾回收器
所有的垃圾回收期都有
STW
(Stop The World) 只是暂停
时间长短不同而已 吞吐量:用户业务代码执行的时间/(业务代码执行的时间+垃圾收集的时间)
吞吐量越大,垃圾收集时间越短,用户代码就可以充分利用CPU资源
jdk1.8默认使用Parallel GC
jdk1.9默认使用G1
- 串行收集器 单线程
- Serial -> ParNew (多线程)
- Serial Old
- 并行收集器 吞吐量优先
- Parallel Scanvenge
- Parallel Old
- 并发收集器 停顿时间优先
- CMS
- G1 jdk1.9之后是默认的
- jdk11 还有一个ZGC(Z Garbage Collector) 停顿时间小于10ms
- 串行收集器 单线程
-
CMS:Concurrent Mark Sweep 并发类的垃圾收集器
初始标记->并发标记->重新标记->并发清除
标记清除
空间碎片 -
G1:Garbage-First Jdk1.9默认 再1.8中比较普遍
垃圾优化,整体上属于
标记整理
算法,不会导致空间碎片Region区域,对堆重新进行了布局,逻辑存在Young、Old、Eden,物理上已经不是隔离的了
初始标记->并发标记->最终标记->筛选回收->应用程序线程
标记整理
减少空间碎片 -
他们之间的收集方式
CMS老年代 Card Table 引用了堆 全盘扫描整个老年代 耗时 有空间碎片
G1优先收集垃圾比较多的区域
region
-
G1设计的初衷
以前GC收集器扫描整个老年代,新生代和老年代需要是连续空间
-
-
如何减少GC的频率
- 适当的增加堆内存的空间
- 合理的设置G1垃圾收集器的停顿时间
- 垃圾回收临界线 -XX:initialtingHeapOccupancyPercent=45(默认)
- 增加垃圾回收线程数量
-
什么样的对象才是垃圾
-
引用计数法
-
可达性分析 GC Root
-
-
如何选择合适的垃圾收集器
- 优先调整堆的大小让服务器自己来选择
- 如果内存小于100M,使用串行收集器
- 如果是单核,并且没有停顿时间要求,使用串行或JVM自己选
- 如果允许停顿时间超过1秒,选择并行或JVM自己选
- 如果相应时间最重要,并且不能超过1秒,使用并发收集器
-
JVM参数
-
标准参数
java -version/ -help
-
-X 参数
非标准参数:JDK版本变动会导致变动
java -Xint/-Xcomp/-Xmixed Hotspot
mixed混合模式 JVM自己选择
-
-XX 参数
-
Boolean类型
-XX:[+/1]name 启动或者停止
-
非Boolean类型
-XX: name=value
-XX: maxHeapSize=100M
-
-
其他参数
-Xms100M = -XX: InitiaHeapSize=100M 初始化堆内存
-Xmx100M = -XX: MaxHeapSize=100M 最大化堆内存
-Xss100M=-XX: ThreadStackSize=100M 栈内存
-
-
内存分析过程中会用到的一些指令
-
JPS 查看当前Java进行
-
Jinfo 查看或者修改JVM参数 试试修改Jinfo -flag name = value PID
-
Jstat class/gc
-
Jstack PID
-
Jmap: 生成堆内存的快照
Jmap -heap PID
生成快照文件: Jmap dump:format = b.file:heap.hprof PID
-
分析内存
-
查看内存工具
-
Jconsole
-
Jvisualvm(windows需要安装插件 Mac直接就可以在上面下载插件)
-
MAT
-
perfma 在线的 dump分析文件
-
-
分析日志工具
- gcviewer
- gc easy 在线网站
-
-
-
垃圾收集发生的时机是什么时候
GC由JVM自己完成,时间不确定,也可以手动调用
System.gc()
,手动调用会有一个问题,强引用类型无法清除掉,就算内存不够用,报异常,也不清除,需要了解强引用、软引用、弱引用、虚引用的区别- Eden区或S区不够用了 Minor GC
- 老年代空间不够用了 Major GC
- 方法区空间不够用了 Full GC
- System.gc()->手动调用
-
评价一个垃圾收集器的好坏
- 停顿时间
- 吞吐量
- GC次数
-
是否选用G1垃圾收集器的判断标准
-
使用G1GC垃圾收集器
-XX:+UseG1GC
-
调整内存大小再获取gc日志分析
-
调整最大停顿时间
-
启动并发GC时,堆内存占用百分比
并发周期,基于整个堆的使用率
-XX: InitiatingHeapOccupancyPercent=45(默认)
-
-
调优G1
- 尽量不调整新生代的大小,否则会破坏停顿时间,JVM是会自己进行调整的
- 停顿时间,不要设置太严格,否则会增加GC次数,影响吞吐量
- 对参数进行调整,增加标记线程的数量 concGCThreads = 10
- Mixe混合调优
- 适当增加堆内存大小
-
如果Full GC频繁怎么办?怎样减少Full GC次数?
- 可以调整新生代:老年代的比例,稍微加大新生代,newRadio默认是2(1:2)
- 调整停顿时间/吞吐量等,让其在新生代就被回收
-
GC次数频繁,你会怎么办?
- 为什么能够知道频繁?GC次数?CPU使用率高了?
- 解决步骤:打印出gc日志->minor GC/major GC 结合工具看一下
- 解决方法:
- 适当增加堆内存的空间
- 选择的垃圾收集器不合适
- set pause time 是不是太严格了 strict/并发周期(堆内存使用率45% 调高一点)
-
CPU持续飙升
- 为什么能看到CPU升高呢?
- 解决步骤:top->id->jstack/jinfo/jmap
- 解决方法:
- 集群
- MQ
- 业务层面,是否是线程死锁
-
OOM怎么解决?
- 如何发现的
- 解决步骤:dump文件,日志->分析dump文件->MAT/其他工具
- 解决方法:
- 调整堆内存空间
-
Young GC会有STW吗?
不管什么GC,都会有Stop The World,只是发生时间的长短不同而已
-
内存泄漏和内存溢出
-
内存泄漏
对象无法得到及时的回收,持续占用内存空间,从而造成内存空间的浪费
-
内存溢出
内存泄漏到一定的成都就会导致内存溢出,但是内存溢出也有可能是大对象导致的
-
内存泄漏和内存溢出OOM有什么区别?
对象得不到回收,导致泄漏累积,最终会变为内存溢出
-
-
方法区中的回收主要是什么内容?
-
分析
方法区里存储的内容是什么?
类信息、静态变量、常量池、没有用的类的信息、常量
-
类的信息什么时候被回收呢?
- 堆里面不再有该类的对象了
- 加载该类的ClassLoader已经被回收了
- java.lang.class对象不再有任何地方引用,反射也不能用–>可以回收,但并不是一定!!
-
-
不可达的对象一定要被收回吗?
GCRoot->请注意 会被标记两次
不可达对象->finalize()->不是垃圾对象,可能会有标记,自救恢复
-
什么是直接内存?
直接内存是在java堆外的,直接向系统申请的内存空间,通常访问直接内存的速度会优于java堆,因此出于性能的考虑,读写频繁的场合可能会考虑使用直接内存
-
安全点和安全区域
-
安全点
线程可以暂停的时间点,一般是耗时较长的执行过程中发生的,不会影响到执行速度,如果在耗时短的执行过程中发生的,会有影响
-
安全区域
就是在一定区域内,都可以进行暂停的发生
-
抢先式中断
目前已经没有虚拟机用这种方式了
-
主动式中断
-