JVM学习笔记8:垃圾收集(垃圾收集算法及垃圾收集器)

一 垃圾收集算法

  1. 标记清除法(Mark-Sweep)

        算法分成标记和清除两个阶段,先标记出要回收的对象,然后统一回收这些对象。形如:

优点:
     简单
缺点是:
     效率不高,标记和清除的效率都不高
    标记清除后会产生大量不连续的内存碎片,从而导致在分配大对象时触发GC
 

2 复制算法(Copying)

       把内存分成两块完全相同的区域,每次使用其中一块,当一块使用完了,就把这块上还存活的对
象拷贝到另外一块,然后把这块清除掉,目前大部分商业虚拟机都采用这种算法来回收新生代。形如

  • 优点是:实现简单,运行高效,不用考虑内存碎片问题
  • 缺点是:内存浪费大,只能使用一半
  • JVM实际实现中,是将内存分为一块较大的Eden区和两块较小的Survivor空间,每次使用Survivor,回收时,把存活的对象复制到另一块Survivor。
  • HotSpot默认的Eden和Survivor比是8:1,也就是每次能用90%的新生代空间
  • 如果Survivor空间不够,就要依赖老年代进行分配担保,把放不下的对象直接进入老年代
  • 分配担保
             分配担保是:当新生代进行垃圾回收后,新生代的存活区放置不下,那么需要把这些对象放置到老年代去的策略,也就是老年代为新生代的GC做空间分配担保。
    a.在发生MinorGC前,JVM会检查老年代的最大可用的连续空间,是否大于新生代所有对象的
              总空间,如果大于,可以确保MinorGC是安全的
    b.如果小于,那么JVM会检查是否设置了允许担保失败,如果允许,则继续检查老年代最大可
              用的连续空间,是否大于历次晋升到老年代对象的平均大小
    c.如果大于,则尝试进行一次MinorGC
    d.如果不大于,则改做一次Full GC
     

 

3 标记整理算法(Mark-Compact)

        由于复制算法在存活对象比较多的时候,效率较低,且有空间浪费,因此老年代一般不会选用复制算法,老年代多选用标记整理算法。
        标记过程跟标记清除一样,但后续不是直接清除可回收对象,而是让所有存活对象都向一端移动,然后直接清除边界以外的内存。形如:

二 垃圾收集器

           收集算法只是内存回收的方法,垃圾收集器就来具体实现这些这些算法并实现内存回收。不同厂商、不同版本的虚拟机实现差别很大,HotSpot中包含的收集器如下图所示:

 

1 Serial(串行)收集器/Serial Old收集器 

                   1:是一个单线程的收集器,在垃圾收集时,会Stop-the-World
                   2:优点是简单,对于单cpu,由于没有多线程的交互开销,可能更高效,是默认的Client模式下的新生代收集器
                   3:使用-XX:+UseSerialGC来开启会使用:Serial + Serial Old 的收集器组合
                   4:新生代Serial使用复制算法,老年代Serial Old 使用标记-整理算法
     GC日志实例:

[GC (Allocation Failure) [DefNew: 640K->64K(704K), 0.0024945 secs] 640K->488K(1984K), 0.0025664 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
[GC (Allocation Failure) [DefNew: 702K->63K(704K), 0.0020210 secs] 1127K->570K(1984K), 0.0020686 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
[GC (Allocation Failure) [DefNew: 628K->60K(704K), 0.0014406 secs] 1134K->829K(1984K), 0.0014826 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
[GC (Allocation Failure) [DefNew: 671K->0K(704K), 0.0015055 secs][Tenured: 1429K->1429K(1472K), 0.0038983 secs] 1440K->1429K(2176K), [Metaspace: 3206K->3206K(1056768K)], 0.0054827 secs] [Times: user=0.00 sys=0.00, real=0.01 secs] 
[GC (Allocation Failure) [DefNew: 1017K->0K(1152K), 0.0013329 secs][Tenured: 2429K->2429K(2576K), 0.0031020 secs] 2447K->2429K(3728K), [Metaspace: 3206K->3206K(1056768K)], 0.0045146 secs] [Times: user=0.02 sys=0.00, real=0.01 secs] 
[GC (Allocation Failure) [DefNew: 1040K->1040K(1216K), 0.0000219 secs][Tenured: 2429K->2730K(2752K), 0.0035755 secs] 3470K->3430K(3968K), [Metaspace: 3206K->3206K(1056768K)], 0.0036585 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
[Full GC (Allocation Failure) [Tenured: 2730K->2701K(2752K), 0.0044666 secs] 3849K->3801K(3968K), [Metaspace: 3206K->3206K(1056768K)], 0.0045212 secs] [Times: user=0.00 sys=0.00, real=0.01 secs] 
[Full GC (Allocation Failure) [Tenured: 2701K->2701K(2752K), 0.0031365 secs] 3801K->3801K(3968K), [Metaspace: 3206K->3206K(1056768K)], 0.0031855 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 

2 ParNew(并行)收集器

                  1:ParNew收集器其实就是Serial收集器的多线程版本。它使用多线程来进行垃圾回收。
                  2:在并发能力好的CPU环境里,它停顿的时间要比串行收集器短;但对于单cpu或并发能力较弱的CPU,由于多线                             程的交互开销,可能比串行回收器更差
                  3:是Server模式下首选的新生代收集器,且能和CMS收集器配合使用
                  4:使用-XX:+UseParNewGC来开启会使用:ParNew + Serial Old的收集器组合
                  5:-XX:ParallelGCThreads:指定线程数,最好与CPU数量一致
                  6:使用复制算法

     GC日志实例:

GC (Allocation Failure) [ParNew: 640K->64K(704K), 0.0012610 secs] 640K->506K(1984K), 0.0013403 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
[GC (Allocation Failure) [ParNew: 702K->63K(704K), 0.0008789 secs] 1145K->605K(1984K), 0.0009153 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
[GC (Allocation Failure) [ParNew: 627K->63K(704K), 0.0006648 secs] 1169K->909K(1984K), 0.0007063 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
[GC (Allocation Failure) [ParNew: 673K->22K(704K), 0.0005780 secs][Tenured: 1493K->1493K(1664K), 0.0026303 secs] 1519K->1493K(2368K), [Metaspace: 3206K->3206K(1056768K)], 0.0034575 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
[GC (Allocation Failure) [ParNew: 937K->105K(1152K), 0.0006858 secs] 2431K->2399K(3644K), 0.0007502 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
[GC (Allocation Failure) [ParNew: 1123K->1123K(1152K), 0.0000196 secs][Tenured: 2293K->2393K(2492K), 0.0041983 secs] 3417K->3394K(3644K), [Metaspace: 3206K->3206K(1056768K)], 0.0042940 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
[Full GC (Allocation Failure) [Tenured: 2694K->2694K(2752K), 0.0028808 secs] 3794K->3794K(3968K), [Metaspace: 3206K->3206K(1056768K)], 0.0029321 secs] [Times: user=0.02 sys=0.00, real=0.00 secs] 
[Full GC (Allocation Failure) [Tenured: 2694K->2701K(2752K), 0.0047404 secs] 3794K->3701K(3968K), [Metaspace: 3206K->3206K(1056768K)], 0.0047801 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
[Full GC (Allocation Failure) [Tenured: 2701K->2701K(2752K), 0.0029718 secs] 3801K->3801K(3968K), [Metaspace: 3206K->3206K(1056768K)], 0.0030227 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
[Full GC (Allocation Failure) [Tenured: 2701K->2701K(2752K), 0.0043294 secs] 3801K->3801K(3968K), [Metaspace: 3206K->3206K(1056768K)], 0.0043789 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 

3 Parallel Scavenge 收集器/Parallel Old收集器


             是一个应用于新生代的、使用复制算法的、并行的收集器,跟ParNew很类似,但更关注吞吐量
(CPU吞吐量就是运行应用代码的时间/总运行时间,这种收集器能最高效率的利用CPU,适合运行后台
应用)
               1:使用-XX:+UseParallelGC来开启新生代Parallel Scavenge收集器
               2:使用-XX:+UseParallelOldGC来开启老年代使用Parallel Old收集器,使用Parallel Scavenge +
                            Parallel Old的收集器组合
               3:-XX:GCTimeRatio:指定运行应用代码的时间占总时间的比例,默认99,即1%的时间用来进行垃圾收集
               4:-XX:MaxGCPauseMillis:设置GC的最大停顿时间
               5:新生代Parallel Scavenge使用复制算法,老年代Parallel Old使用标记-整理算法
GC日志实例:

[GC (Allocation Failure) [PSYoungGen: 511K->488K(1024K)] 511K->496K(1536K), 0.0009177 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
[GC (Allocation Failure) [PSYoungGen: 1000K->504K(1024K)] 1008K->584K(1536K), 0.0020611 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
[GC (Allocation Failure) [PSYoungGen: 1014K->504K(1024K)] 1094K->656K(1536K), 0.0021773 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
[GC (Allocation Failure) [PSYoungGen: 917K->488K(1024K)] 1069K->1000K(2048K), 0.0008948 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
[GC (Allocation Failure) [PSYoungGen: 996K->504K(1024K)] 1508K->1548K(2560K), 0.0008398 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
[Full GC (Ergonomics) [PSYoungGen: 504K->0K(1024K)] [ParOldGen: 1044K->1419K(2560K)] 1548K->1419K(3584K), [Metaspace: 3205K->3205K(1056768K)], 0.0096908 secs] [Times: user=0.03 sys=0.00, real=0.01 secs] 
[GC (Allocation Failure) [PSYoungGen: 512K->428K(1024K)] 1931K->2047K(3584K), 0.0004567 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
[GC (Allocation Failure) [PSYoungGen: 936K->496K(1024K)] 2555K->2523K(3584K), 0.0005715 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
[Full GC (Ergonomics) [PSYoungGen: 496K->0K(1024K)] [ParOldGen: 2027K->2419K(2560K)] 2523K->2419K(3584K), [Metaspace: 3205K->3205K(1056768K)], 0.0052797 secs] [Times: user=0.00 sys=0.00, real=0.01 secs] 
[Full GC (Ergonomics) [PSYoungGen: 508K->500K(1024K)] [ParOldGen: 2419K->2418K(2560K)] 2928K->2919K(3584K), [Metaspace: 3205K->3205K(1056768K)], 0.0081769 secs] [Times: user=0.03 sys=0.00, real=0.01 secs] 
[Full GC (Ergonomics) [PSYoungGen: 500K->500K(1024K)] [ParOldGen: 2518K->2518K(2560K)] 3019K->3019K(3584K), [Metaspace: 3205K->3205K(1056768K)], 0.0032858 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 


4 CMS收集器

               1:分为四个阶段
                                 初始标记:只标记GC Roots能直接关联到的对象
                                 并发标记:进行GC Roots Tracing的过程
                                 重新标记:修正并发标记期间,因程序运行导致标记发生变化的那一部分对象
                                 并发清除:并发回收垃圾对象
               2:在初始标记和重新标记两个阶段还是会发生Stop-the-World
               3:使用标记清除算法,也是一个使用多线程并发收集的垃圾收集器
               4:最后的重置线程,指的是清空跟收集相关的数据并重置,为下一次收集做准备
               5:优点:低停顿、并发执行
               6:缺点:
                        (1)并发执行,对CPU资源压力大
                        (2)无法处理 在处理过程中 产生的垃圾,可能导致FGC
                        (3)采用的标记清除算法会导致大量碎片,从而在分配大对象是可能触发FGC
               7:可设置的参数有:
                        -XX:+UseConcMarkSweepGC:使用ParNew + CMS + Serial Old的收集器组合,Serial Old将作为CMS出错的后                                     备收集器
                       -XX:+ParallelCMSThreads:设定CMS的线程数量,默认是(ParallelGCThreads+3)/4
                       -XX:+CMSInitiatingOccupancyFraction:设置CMS收集器在老年代空间被使用多少后触发回收,默认68%
                       -XX:+UseCMSCompactAtFullCollection:设置CMS收集器在完成垃圾收集后是否要进行一次内存碎片的
                                  整理,默认是开启的
                       -XX:+CMSFullGCsBeforeCompaction:设定进行多少次CMS垃圾收集后,进行一次内存整理
                      -XX:+CMSClassUnloadingEnabled:允许对类元数据进行收集
                      -XX:+UseCMSInitiatingOccupancyOnly:表示只在到达阀值的时候,才进行CMS收集

GC日志实例:

[GC (Allocation Failure) [ParNew: 1081K->128K(1216K), 0.0030805 secs] 1081K->564K(2112K), 0.0031878 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
[GC (Allocation Failure) [ParNew: 1208K->127K(1216K), 0.0010856 secs] 1644K->1189K(2688K), 0.0011187 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
[GC (CMS Initial Mark) [1 CMS-initial-mark: 1062K(1472K)] 1289K(2688K), 0.0003326 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
[CMS-concurrent-mark-start]
[GC (Allocation Failure) [ParNew: 1146K->45K(1216K), 0.0011206 secs] 2208K->2185K(3840K), 0.0011612 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
[GC (Allocation Failure) [ParNew: 1064K->1064K(1216K), 0.0000359 secs][CMS[CMS-concurrent-mark: 0.001/0.003 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
 (concurrent mode failure): 2140K->2529K(2624K), 0.0052513 secs] 3205K->3129K(3840K), [Metaspace: 3206K->3206K(1056768K)], 0.0053702 secs] [Times: user=0.00 sys=0.00, real=0.01 secs] 
[Full GC (Allocation Failure) [CMS: 2729K->2706K(2752K), 0.0054262 secs] 3849K->3806K(3968K), [Metaspace: 3206K->3206K(1056768K)], 0.0054999 secs] [Times: user=0.00 sys=0.00, real=0.01 secs] 
[Full GC (Allocation Failure) [CMS: 2706K->2706K(2752K), 0.0037150 secs] 3806K->3806K(3968K), [Metaspace: 3206K->3206K(1056768K)], 0.0037640 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
[GC (CMS Initial Mark) [1 CMS-initial-mark: 2706K(2752K)] 3806K(3968K), 0.0001726 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
[CMS-concurrent-mark-start]
[CMS-concurrent-mark: 0.001/0.001 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
[CMS-concurrent-preclean-start]
[CMS-concurrent-preclean: 0.001/0.001 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 

  
5 G1(Garbage-First)收集器

            G1是一款面向服务端应用的收集器,与其它收集器相比,具有如下特点:

            1:G1能充分利用多CPU、多核环境硬件优势,尽量缩短STW
            2:G1仍然采用分代的思想,对存活时间较长,经过多次GC仍存活的对象,有不同的处理方式,以获取更好的收集效果
            3:G1整体上采用标记-整理算法局部是通过复制算法,不会产生内存碎片。
            4:G1把内存划分成多个独立的区域(Region),保留了新生代和老年代,但它们不再是物理隔离的,而是一部分Region                           的集合,且不需要Region是连续的
            5:G1的停顿可预测,能明确制定在一个时间段内,消耗在垃圾收集上的时间不能超过多长时间。
            6:G1跟踪各个Redion里面垃圾堆的价值大小,在后台维护一个优先列表,每次根据允许的时间来回收价值最大的区                                 域,从而保证在有限时间内的高效收集
            7:跟CMS类似,也分为四个阶段
                    初始标记:只标记GC Roots能直接关联到的对象
                    并发标记:进行GC Roots Tracing的过程
                    最终标记:修正并发标记期间,因程序运行导致标记发生变化的那一部分对象
                    筛选回收:根据时间来进行价值最大化的回收

           8:使用和配置G1
                         a:-XX:+UseG1GC:开启G1
                         b:-XX:+MaxGCPauseMillis=n:最大GC停顿时间,这是个软目标,

                                   JVM将尽可能(但不保证)停顿小于这个时间
                         c:-XX:+InitiatingHeapOccupancyPercent=n:堆占用了多少的时候就触发GC,默认为45
                        d:-XX:NewRatio=n:默认为2
                        e:-XX:SurvivorRatio=n:默认为8
                         f:-XX:MaxTenuringThreshold=n:新生代到老年代的岁数,默认是15
                        g:-XX:ParallelGCThreads=n:并行GC的线程数,默认值会根据平台不同而不同
                        h:-XX:ConcGCThreads=n:并发GC使用的线程数
                        i:-XX:G1ReservePercent=n:设置作为空闲空间的预留内存百分比,以降低目标空间溢出的
                                     风险,默认值是10%
                       j:-XX:G1HeapRegionSize=n:设置的G1区域的大小。值是2的幂,范围是1MB到32MB。目标是
                                 根据最小的 Java 堆大小划分出约 2048 个区域。


GC日志实例:

[GC pause (G1 Evacuation Pause) (young), 0.0014859 secs]
   [Parallel Time: 1.2 ms, GC Workers: 4]
      [GC Worker Start (ms): Min: 185.0, Avg: 185.0, Max: 185.0, Diff: 0.0]
      [Ext Root Scanning (ms): Min: 0.3, Avg: 0.4, Max: 0.5, Diff: 0.2, Sum: 1.6]
      [Update RS (ms): Min: 0.0, Avg: 0.0, Max: 0.0, Diff: 0.0, Sum: 0.0]
         [Processed Buffers: Min: 0, Avg: 0.0, Max: 0, Diff: 0, Sum: 0]
      [Scan RS (ms): Min: 0.0, Avg: 0.0, Max: 0.0, Diff: 0.0, Sum: 0.0]
      [Code Root Scanning (ms): Min: 0.0, Avg: 0.0, Max: 0.0, Diff: 0.0, Sum: 0.0]
      [Object Copy (ms): Min: 0.5, Avg: 0.6, Max: 0.7, Diff: 0.2, Sum: 2.5]
      [Termination (ms): Min: 0.0, Avg: 0.0, Max: 0.0, Diff: 0.0, Sum: 0.0]
         [Termination Attempts: Min: 1, Avg: 1.3, Max: 2, Diff: 1, Sum: 5]
      [GC Worker Other (ms): Min: 0.1, Avg: 0.1, Max: 0.1, Diff: 0.1, Sum: 0.4]
      [GC Worker Total (ms): Min: 1.1, Avg: 1.1, Max: 1.1, Diff: 0.0, Sum: 4.4]
      [GC Worker End (ms): Min: 186.1, Avg: 186.1, Max: 186.1, Diff: 0.0]
   [Code Root Fixup: 0.0 ms]
   [Code Root Purge: 0.0 ms]
   [Clear CT: 0.0 ms]
   [Other: 0.3 ms]
      [Choose CSet: 0.0 ms]
      [Ref Proc: 0.1 ms]
      [Ref Enq: 0.0 ms]
      [Redirty Cards: 0.0 ms]
      [Humongous Register: 0.0 ms]
      [Humongous Reclaim: 0.0 ms]
      [Free CSet: 0.0 ms]
   [Eden: 1024.0K(1024.0K)->0.0B(1024.0K) Survivors: 0.0B->1024.0K Heap: 1024.0K(2048.0K)->664.1K(2048.0K)]
 [Times: user=0.00 sys=0.00, real=0.00 secs] 


   二 垃圾收集器所用到的算法总结

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值