GC垃圾回收
Posted 肖恩雷
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了GC垃圾回收相关的知识,希望对你有一定的参考价值。
1. 垃圾回收之标记算法
-
可达性分析算法
-
通过判断对象的引用链是否可达来决定对象是否可以被回收
-
可作为GC Root的对象
-
-
方法区中常量引用的对象
-
方法区中的静态属性引用的对象
-
本地方法栈中JNI(Native方法)的引用对象
-
活跃线程的引用对象
-
-
-
引用计数算法
-
优点:执行效率高,程序执行受影响较小
-
缺点:无法检测出循环引用的情况,导致内存泄漏
-
2. 垃圾回收之回收算法
-
标记-清除算法
从根集合进行扫描,对存活的对象进行标记;对堆内存从头到尾进行线性遍历,回收不可达对象内存
缺点:产生大量不连续的碎片化内存
-
复制算法
分为对象面和空闲面,对象在对象面上创建,存活的对象被从对象面复制到空闲面,最后将对象面所有对象内存清除
优点:解决了碎片化问题,顺序分配内存,简单高效,适用于对象存活率低的场景(新生代适用)
-
标记-整理算法
从根集合进行扫描,对存活的对象进行标记;移动所有存活的对象,且按照内存地址依次排列,然后将末端内存地址以后的内存全部回收
优点:避免内存的不连续性,不用设置两块内存互换,适用于存活率高的场景(老年代适用)
-
分代收集算法
按照对象生命周期的不同划分区域以采用不同的垃圾回收算法(垃圾回收算法的组合拳)
3. GC的分类
-
Minor GC
新生代:尽可能快速收集掉那些生命周期短的对象,采用复制算法,包括Eden区和2个Survivor区,即S0区和S1区,其比例为8:1:1,新生代和老年代的比例是1:2
-
对象如何晋级到老年代
-
新生代每经过一次Minor GC垃圾回收后,其存活的对象的年龄就增加1岁,默认达到15岁后该对象就会进入到老年代,也可以通过调整参数-XX:MaxTenuringThreshold来设置进入老年代的阈值。
-
经过多次的Minor GC后Survivor区中存放不下的对象
-
一个对象所占的内存超过了Eden区和Survivor区,该对象会直接晋级到老年代,可以通过参数-XX:PretenuerSizeThreshold设置最大对象的内存,超过该值就会直接进入老年代
-
-
常用调优参数
-
-XX:SurvivorRatio Eden和Survivor的比值,默认是8,也就是Eden占新生代的8/10
-
-XX:NewRatio 老年代和新生代内存的大小的比例
-
-XX:MaxTenuringThreshold 对象从新生代晋升到老年代经过GC次数的最大阈值
-
-
-
Full GC
老年代:生命周期存活较长的对象,一般采用标记-清除算法和标记-整理算法,一般使用Full GC,执行Full GC的同时也伴随着对新生代的垃圾回收
Full GC 比Minor GC慢,但执行频率低
-
触发Full GC的条件
-
老年代空间不足,一个在Eden区存放不下的大对象,会直接放到老年代,如果老年代也存放不下,就会触发Full GC
-
永久代空间不足(只针对KJDK7.0之前版本)
-
CMS GC时出现promotion failed,concurrent mode failure
-
Minor GC晋升到老年代的平均大小大于老年代的剩余空间
-
调用System.gc()
-
使用RMI来进行RPC或管理JDK应用,每小时执行一次Full GC
-
-
4. 常见的垃圾回收器
-
垃圾回收器之间的联系
1.两个收集器之间有连线,表明它们可以搭配使用。
2.其中Serial Old作为CMS出现"Concurrent Mode Failure"失败的后备预案。
3.(红色虚线)由于维护和兼容性测试的成本,再JDK8时将Serial+CMS、ParNew+Serial Old这两个组合声明为废弃,并在JDK9完全取消了这些组合的支 持,即移除。
4.(绿色虚线)JDK14中,弃用Parallel Scavenge+SerialOld组合。删除CMS垃圾回收器。
-
年轻代常见的垃圾回收器
-
Serial 收集器: -XX:+UseSerialGC来开启S该 收集器,采用复制算法
-
单线程收集,进行垃圾回收时,必须暂停所有工作线程
-
简单高效,Client模式下默认的年轻代收集器
-
-
ParNew收集器:-XX:+UseParNewGC来开启该收集器,采用复制算法
-
多线程收集,其余的行为、特点和Serial收集器一样
-
单核执行效率不如Serial,在多核下执行才有优势
-
-
Parallel Scavenge收集器:-XX:+UseParallelGC来开启该收集器,采用复制算法
-
吞吐量=运行用户代码时间/(运行用户代码时间+垃圾收集时间),比如运行了100分钟,其中垃圾回收用了2分钟,则吞吐量=98%
-
比起关注用户线程停顿时间(提升用户体验),更关注系统的吞吐量(适合在后台运算)
-
在多核下执行才有优势,Server模式下默认的年轻代收集器
-
对垃圾回收原理不太了解,以至于在优化过程中遇到问题时,可以在项目启动时设置参数-XX:+UseAdaptiveSizePolicy把内存调优交个JVM来完成
-
-
老年代常见的收集器
-
Serial Old收集器:-XX:+UseSerialOldGC来开启该收集器,采用标记-整理算法
-
单线程收集,垃圾收集时,必须暂停所有工作线程
-
简单高效,Client模式下默认的老年代收集器
-
-
Parallel Old收集器:-XX:+UseParallelOldGC来开启该收集器,采用标记-整理算法
-
多线程,吞吐量优先
-
-
CMS收集器:-XX:+UseConcMarkSweepGC,标记-清除算法
-
G1收集器:-XX:+UseG1GC,复制+标记-整理算法(Garbage First)
-
并发和并行
-
分代收集
-
空间整合
-
可预测的停顿
-
-
-
-
以上是关于GC垃圾回收的主要内容,如果未能解决你的问题,请参考以下文章