Java垃圾回收器工作机制

垃圾回收机制中的算法

  1. 引用计数法
    无法解决循环引用,已被gc放弃
  2. 标记-清除法

    由gc root往下寻找引用,将无引用的内存回收。java中可作为GC Root的对象有

    1. 虚拟机栈中引用的对象(本地变量表)
    2. 方法区中静态属性引用的对象
    3. 方法区中常量引用的对象
    4. 本地方法栈中引用的对象(Native对象)
  3. 标记-整理(压缩)

    在标记清除后整理内存

  4. 复制

    将活动对象复制到另一块内存中,清空这块内存

    eden->Survivor0->Survivor1

  5. 分代

    年轻代-年老代-持久代

    java_gc
    java_gc

    • 年轻代:

      • Serial收集器(复制算法)

        新生代单线程收集器,标记和清理都是单线程,优点是简单高效。

      • ParNew收集器(停止-复制算法)

        新生代收集器,可以认为是Serial收集器的多线程版本,在多核CPU环境下有着比Serial更好的表现。

      • Parallel Scavenge收集器(停止-复制算法)

        并行收集器,追求高吞吐量,高效利用CPU。吞吐量一般为99%, 吞吐量= 用户线程时间/(用户线程时间+GC线程时间)。适合后台应用等对交互相应要求不高的场景。

    • 年老代:

      • Serial Old收集器(标记-整理算法)

        单线程收集器,Serial收集器的老年代版本。

      • Parallel Old收集器(停止-复制算法)

        Parallel Scavenge收集器的老年代版本,并行收集器,吞吐量优先

      • CMS(Concurrent Mark Sweep)收集器(标记-清理算法)

        高并发、低停顿,追求最短GC回收停顿时间,cpu占用比较高,响应时间快,停顿时间短,多核cpu 追求高响应时间的选择

GC的执行机制

由于对象进行了分代处理,因此垃圾回收区域、时间也不一样。GC有两种类型:Scavenge GC和Full GC。

  • Scavenge GC

    一般情况下,当新对象生成,并且在Eden申请空间失败时,就会触发Scavenge GC,对Eden区域进行GC,清除非存活对象,并且把尚且存活的对象移动到Survivor区。然后整理Survivor的两个区。这种方式的GC是对年轻代的Eden区进行,不会影响到年老代。因为大部分对象都是从Eden区开始的,同时Eden区不会分配的很大,所以Eden区的GC会频繁进行。因而,一般在这里需要使用速度快、效率高的算法,使Eden去能尽快空闲出来。

  • Full GC

    对整个堆进行整理,包括Young、Tenured和Perm。Full GC因为需要对整个堆进行回收,所以比Scavenge GC要慢,因此应该尽可能减少Full GC的次数。在对JVM调优的过程中,很大一部分工作就是对于FullGC的调节。

    有如下原因可能导致Full GC:

    1. 年老代(Tenured)被写满
    2. 持久代(Perm)被写满
    3. System.gc()被显示调用
    4. 上一次GC之后Heap的各域分配策略动态变化