尚学堂百战程序员之垃圾回收器

尚学堂百战程序员之垃圾回收器
2018年06月19日 09:36 独一无二的楠竹

一、垃圾收集器

1.Serial收集器

单线程收集器,他进行垃圾收集时,必须暂停其他所有的工作线程,知道它收集结束。简单高效,Serial收集器对于运行在Client模式下的虚拟机来说是一个很好的选择。

2.ParNew收集器

ParNeq收集器其实是Serial收集器的多线程版本,除了多线程收集之外,其他与Serial收集器相比没有太多创新之处,但它却是运行在Server模式下的虚拟机中首选的新生代收集器,除了Serial收集器外,目前只有它能与CMS收集器配合工作。并发与并行:并发是指多条垃圾收集线程并行工作,但此时用户线程仍然处于等待状态。。。。并发:指用户线程与垃圾收集线程同时执行(不一定是并行的,可能会交替执行)。用户程序在继续运行,而垃圾收集程序运行于另外一个CPU上

3.Paraller Scavenge收集器

新生代收集器,使用复制算法的收集器,又是并行的多线程收集器。目标是达到一个可控制的吞吐量。吞吐量=运行用户代码时间/(运行用户代码时间+垃圾回收时间)停顿时间越短就越适合需要与用户交互的程序,良好的响应速度能够提升用户体验,而高吞吐量则可高效率的利用CPU时间,尽快完成程序的运行任务。Paraller Scavenge提供控制最大垃圾收集停顿时间-XX:MaxGCPauseMillis和直接设置吞吐量大小的参数-XX:GCTimeRatio。当-XX:+UseAdaptiveSizePolicy打开时,不需要手动设置新生代大小,晋升老年代对象大小等细节参数了,虚拟机会根据系统运行情况收集性能检测信息,动态调整。这种方式称为GC自适应的调节策略。

4.Serial Old收集器

Serial Old是Serial收集器的老年代版本,同样是单线程收集器,使用标记-清理算法这个收集器主要意义在于给Client模式下的虚拟机使用,如果Server模式下,还有两大用途在JDK1.5版本之前的版本中与Parallel Scavenge收集器搭配使用,另一种用途是作为CMS收集器的后备预案在并发收集发生Concurrent Mode Failure时使用。

5.Parallel Old收集器

Parallel Old是Paraller Scavenge收集器的老年代版本,使用多线程标记整理算法,在注重吞吐量以及CPU资源敏感的场合,优先考虑Paraller Scavenge加Paraller Old收集器。

6.CMS收集器

CMS是以获取最短回收停顿时间为目标的收集器,基于标记清除算法,分为4个步骤:初始标记,并发标记,重新标记,并发清除。初始标记和重新标记人需要stop the world。初始标记仅仅只是标记GC Roots能直接关联到的对象,速度很快,并发标记就进行GC Roots Tracing的过程重新标记就是为了修正并发标记期间因用户程序继续运作导致标记产生变动那部分对象的标记记录,比初始标记时间长一点但远比并发标记时间短。CMS收集器的内存回收过程是与用户线程一起并发执行的。主要优点是并发收集、低停顿,缺点:1、对CPU资源非常敏感,CMS默认启动的回收线程数是(CPU数量+3)/4,当CPU数量很少时会导致程序变慢,虚拟机提供一种“增量式并发收集器,就是在并发标记、清理的时候让GC线程、用户线程交替运行,尽量减少线程的独占资源时间。2、无法处理浮动垃圾(并发清理阶段产生的垃圾),可能出现Concurrent Mode Failure失败而导致另一次Full GC的产生,JDK1.5默认当老年代使用了68%的空间后就会激活。在JDK1.6中已经提升至92%,若CMS运行期间预留内存不足会出现Concurrent Mode Failure,虚拟机启动预案,临时启用Serial Old收集器来重新进行老年代的垃圾收集,这样停顿时间较长。3、收集结束后会有大量空间碎片,可以设置多少次不压缩的Full GC后,跟着来一次带压缩的。

7.G1收集器

特点:并行与并发、分代收集、空间整合、可预测的停顿G1收集器时,java堆的内存布局与其他收集器有很大的差别,他将整个java堆分为多个大小相等的独立区域,新生代与老年代不在是物理隔离,都是一部分Region集合G1跟着各个Region里面的垃圾堆价值大小(回收所获得的空间大于以及回收所需时间的经验值)在后台维护一个优先列表,每次根据允许的收集时间,优先回收价值最大的Region     G1中虚拟机使用Remembered Set来避免全堆扫描。虚拟机发现程序在对reference类型的数据进行写操作时,会产生一个Write Barrier暂时中断写操作,检查Reference引用的对象是否处于不同Region之中,如果是,便通过CardTable把相关引用信息记录到被引用对象所属的Region的Remembered Set中,进行内存回收时,在GC根节点的枚举范围中加入Remembered Set即可保证不对全堆扫描不会有遗漏如果不计算维护Remembered Set的操作,G1收集器的运作大致可分为:初始标记、并发标记、最终标记、筛选回收。

二、内存分配与回收策略

1、对象优先在Eden分配

多数情况下,对象在新生代Eden区中分配,当Eden区没有足够空间进行分配时,将发起一次Minor GC.新生代GC(Minor GC)老年代GC(Major GC):出现Major GC,经常会伴随至少一次Minor GC(但非绝对,在Parallel  Scavenge收集器的收集策略里就有直接进行Major GC的策略选择过程)

2、大对象直接进入老年代

所谓大对象是指,需要大量连续内存空间的Java对象,最典型的大对象就是那种很长的字符串以及数组通过-XX:PretenureSizeThreshold参数,令大于这个设置值的对象直接在老年代分配这样就避免在Eden区及两个Survivor区之间发生大量的内存复制。参数只对Serial和ParNew两款收集器有效,Parallel Scaveng收集器不认识这个参数,Parallel Scavenge收集器一般并不需要设置,如遇到必须使用此参数的场合,可以考虑使用ParNew加CMS的收集器组合

3、长期存活的对象将进入老年代

既然虚拟机才有分代收集的思想来管理内存,那么内存回收时就必须能识别哪些对象应放在新生代,哪些对象应该放在老年代中。虚拟机给每个对象定义一个对象年龄计数器,如果对象在Eden出生并经过一次Minor GC后仍然存在并能被Survivor容纳的话,将被移动到Survivor空间中,年龄设为1,每熬过一次Minor GC之后,年龄就加1.年龄增加到一定程度就会被晋升到老年代中。

4、动态对象年龄判定

为了更好地适应不同程序的内存状况,虚拟机并不是永远地要求对象的年龄必须达到MaxTenuringThreshold才能晋升老年代。如果在Survivor空间中相同年龄所有对象大小的和大于Survivor空间的一般,年龄大于或等于该年龄的对象就可以直接进入老年代,无需达到MaxTenuringThreshold中要求的年龄。

5、空间分配担保

发生Minor GC之前,虚拟机会先检查老年代最大可用的连续空间是否大于新生代所有对象总空间,如果成了,则Minor GC是安全的,若不成立,则虚拟机查看HandlePromotionFailure设置值是否允许担保失败,如果允许,则继续坚持老年代最大可用的连续空间是否大于历次晋升到老年代对象的平均大小,若大于,则尝试进行一次Minor GC,如果小于,或不允许冒险,那这时要改为进行一次Full GC。JDK 6 Update 24之后的规则变为只要老年代的连续空间大于新生代对象总大小或者历次晋升的平均大小就会进行Minor GC,否则将会进行Full GC。

后记:对于大部分转行的人来说,找机会把自己的基础知识补齐,边工作边补基础知识,真心很重要。

我们相信人人都可以成为一个IT大神,现在开始,选择一条阳光大道,助你入门,学习的路上不再迷茫。这里是北京尚学堂,初学者转行到IT行业的聚集地。"

财经自媒体联盟更多自媒体作者

新浪首页 语音播报 相关新闻 返回顶部