JVM垃圾回收器

以下内容引自:实战JAVA虚拟机 JVM故障诊断与性能优化  一书

串行垃圾回收器:单线程进行垃圾回收的回收器。分为:新生代串行回收器和老年代串行回收器。

并行垃圾回收器:分为新生代ParNew回收器,新生代ParallelGC回收器,老年代ParallelOldGC回收器。

CMS回收器

G1回收器

新生代:存放年轻对象的堆空间。年轻对象指刚刚创建的,或者经历垃圾回收次数不多的对象。

老年代:存放老年对象的堆空间。老年对象指经历过多次垃圾回收依然存活的对象。

新生代串行垃圾回收器

特点:

  • 仅仅使用单线程进行垃圾回收。
     
  • 独占式的垃圾回收(即:应用程序的所有线程都停止工作,进行等待)。

使用了复制算法的思想。新生代分为eden空间,from空间,to空间3部分。其中from和to空间可以视为用于复制的两块大小相同,地位相等,且可进行角色互换的空间块。from和to空间也称为survivor空间,即幸存者空间,用于存放未被回收的对象。

-XX:+UseSerialGC       新生代,老年代都使用串行回收器

当虚拟机在Client模式下运行时,它是默认的垃圾收集器。

串行垃圾回收器虽然古老,但久经考验。在大多数情况下,其性能表现是相当不错的。

老年代串行回收器

使用标记压缩算法,也是一个串行的,独占式的垃圾回收器。由于老年代垃圾回收通常会使用比新生代回收更长的时间,因此,在堆空间较大的应用程序中,一旦老年代串行收集器启动,应用程序很可能会因此停顿较长的时间。

虽然如此,作为老牌的垃圾回收器,老年代串行回收器可以和多种新生代回收器配合使用,同时它也可以作为CMS回收器的备用回收器。

若要启用老年代串行回收器,可以尝试使用以下参数:

-XX:+UseSerialGC       新生代,老年代都使用串行回收器

-XX:+UseParNewGC   新生代使用ParNew回收器,老年代使用串行回收器

-XX:+UseParallelGC    新生代使用ParallelGC回收器,老年代使用串行回收器

新生代ParNew回收器

只是简单地将串行回收器多线程化,它的回收策略,算法以及参数和新生代串行回收器一样。ParNew回收器也是独占式的回收器,在收集过程中,应用程序会全部暂停。但由于并行回收器使用多线程进行垃圾回收,因此,在并发能力较强的CPU上,它产生的停顿时间要短于串行回收器,而在单CPU或者并发能力较弱的系统中,并行回收器的效果不会比串行回收器好,由于多线程的压力,它的实现表现很可能比串行回收器差。

-XX:+UseParNewGC   新生代使用ParNew回收器,老年代使用串行回收器

-XX:+UseConcMarkSweepGC    新生代使用ParNew回收器,老年代使用CMS

 

新生代ParallelGC回收器

也是使用复制算法的收集器,多线程,独占式的回收器。ParallelGC回收器有一个重要的特点:它非常关注系统的吞吐量。

-XX:+UseParallelGC    新生代使用ParallelGC回收器,老年代使用串行回收器

-XX:+UseParallelOldGC    新生代使用ParallelGC回收器,老年代使用ParallelOldGC回收器

ParallelGC回收器提供了两个重要的参数用于控制系统的吞吐量。

-XX:MaxGCPauseMillis:设置最大垃圾收集停顿时间。

-XX:GCTimeRatio:设置吞吐量大小。

ParallelGC回收器支持一种自适应的GC调节策略。使用-XX:+UseAdaptiveSizePolicy可以打开自适应GC策略。在这种模式下,新生代的大小,eden和survivior的比例,晋升老年代的对象年龄等参数会被自动调整,以达到在堆大小,吞吐量和停顿时间之间的平衡点。在手式调优比较困难的场合,可以直接使用这种自适应的方式 ,仅指定虚拟机的最大堆,目标吞吐量(GCTimeRatio)和停顿时间(MaxGCPauseMillis),让虚拟机自己完成调优工作。

 

老年代ParallelOldGC回收器

老年代ParallelOldGC回收器也是一种多线程并发的收集器。与新生代ParallelGC回收器一样,它也是一种关注吞吐量的回收器。

ParallelOldGC回收器使用标记压缩算法 ,它在JDK1.6中才可以使用。

-XX:+UseParallelOldGC    新生代使用ParallelGC回收器,老年代使用ParallelOldGC回收器

 

CMS回收器

多线程,非独占式,应用于老年代,主要关注于系统停顿时间,使用标记清除算法,主要关注于系统停顿时间。

主要工作步骤:

 

并发重置:是指在垃圾回收完后,重新初始化CMS数据结构和数据,为下一次垃圾回收做好准备。

在整个CMS回收过程中,默认情况下,在并发标记之后,会有一个预清理的操作(也可以关闭开关-XX:-CMSPrecleaningEnabled,不进行预清理)。预清理是并发的,除了为正式清理做准备和检查以外,预清理还会尝试控制一次停顿时间。由于重新标记是独占CPU的,如果新生代GC之后,立即触发一次重新标记,那么一次停顿时间可能很长。为了避免这种情况,预处理时,会刻意等待一次新生代GC的发生,然后根据历史性能数据预测下一次新生代GC可能发生的时间,然后在当前时间和预测时间的中间时刻,进行重新标记。这样,从最大程度上避免新生代GC和重新标记重合,尽可能减少一次停顿时间。

-XX:+UseConcMarkSweepGC    新生代使用ParNew回收器,老年代使用CMS

CMS默认启动的并发线程数是((ParallelGCThreads+3)/4)。ParallelGCThreads表示GC并行时使用的线程数量,如果新生代使用ParNew,那么ParallelGCThreads也就是新生代GC的线程数量。这意味着有4个ParallelGCThreads时,只有一个并发线程,而两个并发线程时,有5到8个ParallelGCThreads线程数。

并发线程数量也可以通过 -XX:ConcGCThreads 或者 -XX:ParallelCMSThreads 参数手工设定。当CPU资源比较紧张时,受到CMS回收器线程的影响,应用系统的性能在垃圾回收阶段可能会非常糟糕。

注意:并发是指收集器和应用线程交替执行,并行是指应用程序停止,同时由多个线程一起执行GC。因此并行回收器不是并发的。因为并行回收器执行时,应用程序完全挂起,不存在交替执行的步骤。

当堆内存使用率达到某一阈值时便开始进行回收,以确保应用程序在CMS工作过程中,依然有足够的空间支持应用程序运行。这个阈值可以用-XX:CMSInitiationgOccupancyFraction来指定,默认是68。即当老年代的空间使用率达到68%时,会执行一次CMS回收。如果应用程序的内存使用率增长很快,在CMS的执行过程中,已经出现了内存不足的情况 ,此时,CMS回收就会失败,虚拟将启动老年代串行收集器进行垃圾回收。如果这样,应用程序将完全中断,直到垃圾回收完成,这时,应用程序的停顿时间可能会较长。

由于CMS使用标记清除法,将会造成大量内存碎片,离散的可用空间无法分配较大的对象。在这种情况 下,即使堆内存仍然有较大的剩余空间,也可能会被迫进行一次垃圾回收,以换取一块可用的连续内存。针对这种情况,CMS回收器不提供了几个用于内存压缩整理的参数。

-XX:+UseCMSCompactAtFullCollection开关可以使CMS在垃圾收集完成后,进行一次内存碎片整理,内存碎片的整理不是并发进行的。-XX:CMSFullGCsBeforeCompaction参数可以用于设定进行多少次CMS回收后,进行一次内存压缩。

在使用CMS回收器时,如果需要回收Perm区,那么默认情况下,还是需要触发一次Full GC的,如果 希望使用CMS回收Perm区,则必须打开-XX:+CMSClassUnloadingEnabled开关。

 

G1回收器

G1回收器是在JDK1.7中正式使用的全新的垃圾回收器,从长期目标来看,它是为了取代CMS回收器。G1回收器拥有独特的垃圾回收策略,从分代上看,G1依然属于分代垃圾回收器,它会区分年轻代和老年代,依然有eden区和survivor区,但从堆 的结构上看,它并不要求整个eden区,年轻代或者老年代都连续,它使用了分区算法,特点如下 :

  • 并行性:G1在回收期间,可以由多个GC线程同时工作,有效利用多核计算能力。
     
  • 并发性:G1拥有与应用程序交替执行的能力,部分工作可以和应用程序同时执行,因此一般来说,不会在整个回收期间完全阻塞应用程序。
     
  • 分代GC:G1依然是一个分代收集器,但是和之前回收器不同,它同时兼顾年轻代和老年代。对比其他回收器,它们或者工作在年轻代或者老年代。这里是一个很大的不同。
     
  • 空间整理:G1在回收过程中,会进行适当的对象移动,不像CMS,只是简单地标记清理对象,在若干次GC后,CMS必须进行一次碎片整理。而G1不同,它每次回收都会有效地复制对象,减少空间碎片。
     
  • 可预见性:由于分区的原因,G1可以只选取部分区域进行内存回收,这样缩小了回收的范围,因此对于全局停顿也能得到较好的控制。
     

G1收集器将堆进行分区,划分一个个的区域,每次收集的时候,只收集其中几个区域,以此来控制垃圾回收产生的一次停顿时间。G1的收集过程可能有4个阶段:

  • 新生代GC
     
  • 并发标记周期
     
  • 混合收集
     
  • 如果需要,可能会进行Full GC

新生代GC:主要工作是回收eden区和survivor区。一旦eden区被占满,新生代GC就会启动。回收后,所有的eden区都应该被清空,而survivor区会被收集一部分数据,但是应该至少仍然存活一个survivor区,类比其它的新生代收集器,这一点似乎并没有太大变化。另一个重要的变化是老年代的区域增多,因为部分survivor区或者eden区的对象可能会晋升到老年代。

 

G1的并发标记周期:G1的并发阶段和CMS有点类似,它们都是为了降低一次停顿时间,而将 可以和应用程序并发的部分单独提取出来执行,并发标记周期可以分为以下几步:

  • 初始标记:标记从根据节点直接可达的对象。这个阶段会伴随一次新生代GC,它是会产生STW的,应用程序线程在这个阶段必须停止执行。
     
  • 根区域扫描:由于初始标记必然会伴随一次新生代GC,所以在初始化标记后,eden被清空,并且存活对象被移入survivor区。在这个阶段,将扫描由survivor区直接可达的老年代区域,并标记这些直接可达的对象。这个过程是可以和应用程序并发执行的。但是根据区域扫描不能和新生代GC同时进行,因为根区域扫描依赖survivor区的对象,而新生代GC会修改这个区域,因此如果恰巧在此时需要进行新生代GC,GC就需要等待根区域扫描结束后才能进行,如果发生这种情况,这次新生代GC的时间就会延长。
     
  • 并发标记:和CMS类似,并发标记将会扫描并查找整个堆的存活对象,并做好标记。这是一个并发的过程,并且这个过程可以被一次新生代GC打断。
     
  • 重新标记:和CMS一样,重新标记也是会产生STW的。由于在并发标记过程中,应用程序依然在运行,因此标记结果可能需要进行修正,所以在此对上一次的标记结果进行补充。在G1中,这个过程使用SATB(Snapshot-At-TheBeginning)算法完成。即G1会在标记之初为存活对象创建一个快照,这个快照有助于加速重新标记的速度。
     
  • 独占清理:这个阶段是会引起STW的。它将计算各个区域的存活对象和GC回收比例并进行排序,识别可供混合回收的区域。在这个阶段,还会更新记忆集(Remember Set)。该阶段给出了需要被混合回收的区域并进行了标记,在混合回收阶段需要这些信息。
     
  • 并发清理阶段:这里会识别并清理完全空闲的区域这是并发的清理,不会引起停顿。

混合回收:在并发标记周期中,虽然有部分对象被回收,但是总体上来说,回收的比例是相当低的。但是在并发标记周期后,G1已经明确知道哪些区域含有比较多的垃圾对象,在混合回收阶段,就可以专门针对这些区域进行回收。当然,G1会优先回收垃圾比例较高的区域,因为回收这些区域的性价比也比较高。而这也正是G1名字的由来。G1全称为Garbage First Garbage Collector,直译为垃圾优先的垃圾回收器。这个阶段,既会执行正常的年轻代GC,又会选取一些被标记的老年代区域进行回收,它同时处理了新生代和老年代。被清理区域中的存活对象会被移动到其他区域,这样的好处是可以减少空间碎片。

混合GC会执行多次,直到回收了足够多的内存空间,然后,它会触发一次新生代GC。新生代GC后,又可能会发生一次并发标记周期处理,最后,又会引起混合GC的执行。如图 :

 

必要时的Full GC:和CMS类似,并发收集由于让应用程序和GC线程交替工作,因此,总是不能完全避免在特别繁忙的场合出现在回收过程中内存不充足的情况。当遇到这种情况时,G1也会转入一个Full GC进行回收。

此外,如果在混合GC时发生空间不中或者在新生代GC时,survivor区域和老年代区域无法容纳幸存对象,都会导致一次FullGC产生。

-XX:+UseG1GC     标记打开G1收集器开关

-XX:MaxGCPauseMillis    它用于指定目标最大的停顿时间。如果任何一次停顿超过这个设置时,G1就会尝试调整新生代和老年代的比例,调整堆 大小,调整晋升年龄等手段,试图达到预设目标。

-XX:ParallelGCThreads    用于设置并行回收时,GC的工作线程数量

-XX:InitiatingHeapOccupancyPercent 可以指定当整个堆使用率达到多少时,触发并发标记周期的执行,默认45,整个堆占用率达到45%时,执行并发标记周期。

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值