JavaGC垃圾回收

垃圾回收 Garbage Collection

垃圾回收的主要目的 — 清除不再使用的对象,自动释放内存。

堆分成两大块:新生代和老年代

对象产生之初,在新生代;步入暮年时,进入老年代,但是老年代也接纳在新生代无法容纳的超大对象。

当Eden 区装填满的时候,会触发 Young Garbage Collection(GYC)。

如果YGC 要移送的对象大于 Survivor 区容量的上限,则直接移交给老年代。

每个对象都有一个计数器,每次YGC 都会加1。-XX:MaxTenuringThreshold 参数(默认值:15)能配置计算器的值到达某个阈值的时候,对象从新生代晋升到老年代。

进入老年代(Tenure)的3种情况:

  • 新生代无法容纳的超大对象;
  • YGC要移送的对象大于Survivor区容量的上限;
  • 对象计数器(每次YGC都会加1),超过了MaxTenuringThreshold参数阈值;
  • GC Roots

    为了判断对象释放存活,JVM 引入了GC Roots。

    如果一个对象与GC Roots 之间没有直接或间接的引用关系,就判断这些对象“死缓”,是可以被回收的。

    什么对象可以作为GC Roots 呢?

    比如,类静态属性中引用的对象、常量引用的对象、虚拟机栈中引用的对象、本地方法栈中引用的对象等。

    Mark-Copy 算法

    为了能够并行地标记和整理,将Survivor空间分为两块,每次只激活其中一块,垃圾回收时,只需要把存活的对象复制到另一块未激活空间上,将未激活空间标记为已激活,将已激活空间标记为未激活,然后清除原空间中的原对象。

    堆内存空间分为较大的Eden和两块较小的Survivor,每次只使用Eden 和 Survivor 区的一块。

    Mark-Copy 现作为主流的YGC算法,进行新生代的垃圾回收。

    垃圾回收器(Garbage Collector)

    有Serial、CMS、G1等等。

    Serial 回收器

    是一个主要应用于YGC的垃圾回收器,采用串行单线程的方式完成GC任务,其中Stop The Worled(简称STW),即垃圾回收的某个阶段会暂停整个应用程序的执行。

    FGC 的时间相对较长,频繁FGC 会严重影响应用程序的性能。

    ParNew(并行GC)回收器

    ParNew收集器其实就是serial收集器的多线程版本,除了使用多条线程进行垃圾收集之外,其余行为与Serial收集器一样。

    CMS(Concurrent Mark Sweep)回收器

    回收停顿时间比较短。

    CMS 回收器是基于“标记-清除”算法实现的,因此产生大量的空间碎片,整个收集过程大致分为4个步骤:

    1. 初始标记(CMS initial mark)

    2. 并发标记(CMS concurrenr mark)

    3. 重新标记(CMS remark)

    4. 并发清除(CMS concurrent sweep)

    其中初始标记、重新标记这两个步骤仍然需要停顿其他用户线程。

    G1 回收器

    G1(Garbage First)垃圾回收器是用在heap memory很大的情况下,把heap划分为很多相同大小的region块,然后并行的对其进行垃圾回收。

    包括:Eden、Survivor、Tenured、Humongous(大对象) 4种类型。

    G1垃圾回收器在清除实例所占用的内存空间后,还会做内存压缩。

    G1垃圾回收器回收region的时候基本不会STW,优先回收垃圾最多的区域。

    G1 采用的是 Mark-Copy 算法。

    一个region有可能属于Eden,Survivor或者Tenured内存区域。图中的E表示该region属于Eden内存区域,S表示属于Survivor内存区域,T表示属于Tenured内存区域。图中空白的表示未使用的内存空间。G1垃圾收集器还增加了一种新的内存区域,叫做Humongous内存区域,如图中的H块。这种内存区域主要用于存储大对象-即大小超过一个region大小的50%的对象。

    在G1 垃圾回收器中,年轻代的垃圾回收过程使用 Mark-Copy 算法。

    把Eden 区和 Survivor 区的对象复制到新的Survivor 区域。

    对于年老代上的垃圾收集,G1垃圾收集器也分为4个阶段,基本跟CMS垃圾收集器一样,但略有不同:

    Initial Mark阶段 – 同CMS垃圾收集器的Initial Mark阶段一样,G1也需要暂停应用程序的执行,它会标记从根对象出发,在根对象的第一层孩子节点中标记所有可达的对象。但是G1的垃圾收集器的Initial Mark阶段是跟minor gc一同发生的。也就是说,在G1中,你不用像在CMS那样,单独暂停应用程序的执行来运行Initial Mark阶段,而是在G1触发minor gc的时候一并将年老代上的Initial Mark给做了。

    Concurrent Mark阶段 – 在这个阶段G1做的事情跟CMS一样。但G1同时还多做了一件事情,就是如果在Concurrent Mark阶段中,发现哪些Tenured region中对象的存活率很小或者基本没有对象存活,那么G1就会在这个阶段将其回收掉,而不用等到后面的clean up阶段。这也是Garbage First名字的由来。同时,在该阶段,G1会计算每个 region的对象存活率,方便后面的clean up阶段使用 。

    Remark阶段 – 在这个阶段G1做的事情跟CMS一样, 但是采用的算法不同,G1采用一种叫做SATB(snapshot-at-the-begining)的算法能够在Remark阶段更快的标记可达对象。

    Clean up/Copy阶段 – 在G1中,没有CMS中对应的Sweep阶段。相反 它有一个Clean up/Copy阶段,在这个阶段中,G1会挑选出那些对象存活率低的region进行回收,这个阶段也是和minor gc一同发生的,如下图所示:

    从上图分析:

    E、S region 复制到新的Survivor 区域;

    T 经过回收,复制存放的对象到新的Tenured 区域;

    声明:本站部分文章内容及图片转载于互联 、内容不代表本站观点,如有内容涉及侵权,请您立即联系本站处理,非常感谢!

    (0)
    上一篇 2019年4月6日
    下一篇 2019年4月6日

    相关推荐