深入理解Java (三) 垃圾回收器

一、垃圾收集器

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。

6、垃圾收集器参数总结

参数 说明
UseSerialGC 虚拟机运行在Client模式下的默认值,打开此开关后,使用Serial+Serial Old的收集器组合进行内存回收
UseParNewGC 打开此开关后,使用ParNew+Serial Old的收集器组合进行内存回收
UseConcMarkSweepGC 打开此开关后,使用ParNew+CMS+Serial Old的收集器组合进行内存回收。Serial Old收集器将作为CMS收集器出现Concurrent Mode Failure失败后的后备收集器使用
UseParallelGC 虚拟机运行在Server模式下的默认值,打开此开关后,使用Parallel Scavenge + Serial Old(PS MarkSweep)的收集器组合进行内存回收
UseParallelOldGC 打开此开关后,使用Parallel Scavenge + Parallel Old的收集器组合进行内存回收
SurvivorRatio 新生代中Eden区域与Survivor区域的容量比值,默认值为8,代表Eden:Survivor=8:1
PretenureSizeThreshold 直接晋升到老年代的对象大小,设置这个参数后,大于这个参数的对象将直接在老年代分配
MaxTenuringThreshold 晋升到老年代的对象年龄,每个对象在坚持过一次Minor GC之后,年龄就增加1,当超过这个参数时就进入老年代
UseAdaptiveSizePolicy 动态调整Java堆中各个区域的大小以及进入老年代的年龄
HandlePromotionFailure 是否允许分配担保失败,即老年代的剩余空间不足以应付新生代的整个Eden和Survivor区的所有对象都存活的极端情况
ParallelGCThreads 设置并行GC时进行内存回收的线程数
GCTimeRatio GC时间占总时间的比率,默认值为99,即允许1%的GC时间。仅在使用Parallel Scavenge收集器时生效
MaxGCPauseMillis 设置GC的最大停顿时间,仅在使用Parallel Scavenge收集器时生效
CMSInitingOccupancyFraction 设置CMS收集器在老年代空间被使用多少后触发垃圾收集。默认值为68%,仅在使用CMS收集器时生效
UseCMSCompactAtFullCollection 设置CMS收集器在完成垃圾收集后是否要进行一次内存碎片整理,仅在使用CMS收集器时生效
CMSFullGCsBeforeCompaction 设置CMS收集器在进行若干次垃圾收集后再启动一次内存碎片整理。仅在使用CMS收集器时生效

三、SUN JDK监控和故障处理工具

参数 说明
jps jvm process status tool,显示指定系统内所有的hotspot虚拟机进程
jstat jvm statistics monitoring tool,用于收集hotspot虚拟机各方面的运行数据
jinfo configuration info for java,显示虚拟机配置信息
jmap memory map for java,生成虚拟机的内存转储快照(heapdump文件)
jhat jvm heap dump browser,用于分析heapmap文件,它会建立一个http/html服务器

让用户可以在浏览器上查看分析结果
jstack | stack trace for java ,显示虚拟机的线程快照

猜你喜欢

转载自blog.csdn.net/u013305783/article/details/80728342
今日推荐