发生YGC时的一些细节

作者: 美团Java | 来源:发表于2017-10-23 20:20 被阅读1335次

简书 占小狼
转载请注明原创出处,谢谢!

周末抽空把YGC的源码实现重新看了一遍,发现细节远比知道的多...

首先要知道,什么情况会导致YGC的发生?最常见的情况是在年轻代分配内存时,出现空间不足,这里的内存分配,有可能是TLAB,也有可能是一个对象(该对象在TLAB中放不下,但虚拟机不想重新申请TLAB,就在Eden区分配)

1、如果触发的YGC顺利执行完,期间没有发生任何问题,垃圾回收完成后,正常的分配内存。

2、如果YGC刚要开始执行,却不幸的发生了JNI的GC locker,本次的YGC会被放弃,如果是给对象分配内存,会在老年代中直接分配内存,如果是TLAB的话,就要等JNI结束了。

3、如果没有JNI的干扰,在YGC过程中,对象年纪达到阈值,正常晋升,或to空间不足,对象提前晋升,但老年代又没这么多空间容纳晋升上来的对象,这时会发生“promotion failed”,而且eden和from区的空间没办法清空, 把from区和to区进行swap,所以当前eden和from的使用率都是接近100%的,如果当前是给对象(非TLAB)申请内存,会继续触发一次老年代的回收动作,下面是一个例子:

/**
 * -Xmx20m -Xms20m -Xmn14m -XX:+UseParNewGC  -XX:+UseConcMarkSweepGC
 *-XX:+UseCMSInitiatingOccupancyOnly  -XX:CMSInitiatingOccupancyFraction=75
 *-XX:+PrintGCDetails -XX:+PrintGCDateStamps -XX:+PrintHeapAtGC
 */
public class JVM {

    private static final int _1MB = 1024 * 1024;
    private static final int _1K = 1024;

    public static void main(String[] args) throws Exception {
        byte[][] arr = new byte[10000][];
        for (int i = 0; i< 1200; i++) {
            arr[i] = new byte[10* _1K];
        }
        System.in.read();
    }
}

把年轻代设置的大点,制造“promotion failed”,下面是gc日志:

1、“promotion failed” 如期到来。
2、对老年代进行了一次回收,这次回收有两种方式,一种是compact,另一种是mark-sweep,显然第一种会进行内存的压缩操作,第二种只进行标记清除。到底会使用哪一种,会进行如下判断:

其中UseCMSCompactAtFullCollection默认是开启的,而且CMSFullGCsBeforeCompaction默认是0,所以如果没有重新设置该参数的话,按理说,每次都是会进行compact操作,如果CMSFullGCsBeforeCompaction被设置成一个大于0的值,还有其它条件可以导致compact,一个是如System.gc,另一个是发生了promotion failed,还有其它等等。

本例子中虽然使用了-XX:+UseConcMarkSweepGC,但是不会使用并发的CMS算法,如果当前CMS的background collect已经开始执行,当前GC线程会抢过执行权,并记录“concurrent mode failed”。

如果需要compact,采用单线程的Serial GC进行回收,该算法实现在genMarkSweep.cpp

如果不需要compact,则执行一个标记-清除的过程,实现在CMSCollector::collect_in_foreground中。

3、同样对永久带也来了一次回收

从这个打印出来的日志可以发现,本次的YGC是分配对象时触发的,而不是TLAB(因为在JVM运行过程中,会动态调整TLAB的大小和最大浪费空间),虽然日志中没有FULL GC的字样,其实执行的就是一次full gc过程。

本来我一直纳闷为啥TLAB的分配,会导致老年代的回收,因为如果是TLAB的话,老年代的should_allocate方法实现如下:

virtual bool should_allocate(size_t word_size, bool is_tlab) {
    bool result = false;
    size_t overflow_limit = (size_t)1 << (BitsPerSize_t - LogHeapWordSize);
    if (!is_tlab || supports_tlab_allocation()) {
      result = (word_size > 0) && (word_size < overflow_limit);
    }
    return result;
  }

其中is_tlab为true,supports_tlab_allocation()为false,所以不会继续对老年代进行回收。


渐行渐远,细节远不止这些,不要在细节中迷失了自己...

相关文章

  • 发生YGC时的一些细节

    简书 占小狼转载请注明原创出处,谢谢! 周末抽空把YGC的源码实现重新看了一遍,发现细节远比知道的多... 首先要...

  • JVM --- 垃圾回收

    一、YGC和full GC的区别 YGC(minor GC):只针对新生代区域进行GC,发生得非常频繁,回收速度也...

  • 覆写finalize()引起的ygc问题

    服务性能优化,发现有个服务的ygc次数和单次ygc耗时明显比同类型服务高。 通过jstat(jstat -gc...

  • YGC02+31+烟火白佳莹

    YGC02+31+烟火白佳莹 ...

  • jvm 优化篇-(1)-StringTable会影响YGC,老铁

    为什么要挖StringTable的坟头?先安无事不好么? YGC是一个复杂的过程,本就无从下手,凡是能影响YGC性...

  • 探索StringTable提升YGC性能

    很久很久以前看过笨神的一篇文章JVM源码分析之String.intern()导致的YGC不断变长,其原因是YGC过...

  • Ⅳ.GC

    1.GC简介 GC,又称YGC,只针对新生代的GC;FGC,GC后不满足对象存储会发生FGC,针对新生代,养老代,...

  • Android Note - 代码优化

    这篇主要讲一些平时写代码时优化的小技巧。虽然看上去都是一些很小的细节,但是积少成多,量变到一定程度也会发生质变,积...

  • YGC和FGC是什么

    1.YGC和FGC是什么 YGC :对新生代堆进行gc。频率比较高,因为大部分对象的存活寿命较短,在新生代里被回收...

  • 记一次 GC 优化, JVM 调参数过程

    排查到的问题:新生代增长速度很快, 几分钟累计了近百GB, 导致YGC 发生频繁, 越 20-30秒一次. 仅仅如...

网友评论

  • Coffeelong:在学习gc时使用这段代码分析gc日志,实际进行了两次的gc,理解应该是一次gc,将3个2mb的小对象移动到老年代,4mb新对象直接放在eden区域,希望大家帮助我理解下
    /**
    * jvm args: -Xms20M -Xmx20M -Xmn10M -XX:+PrintGCDetails -XX:SurvivorRatio=8 -XX:UseSerialGC
    * 说明:JDK为1.7
    */
    public static void minorGC() {
    byte[] alloction1, alloction2, alloction3, alloction4;
    alloction1 = new byte[2 * _1MB];
    alloction2 = new byte[2 * _1MB];
    alloction3 = new byte[2 * _1MB];
    alloction4 = new byte[4 * _1MB];
    }
    ***********GC日志*********
    [GC[DefNew: 7021K->1024K(9216K), 0.0056361 secs] 7021K->3223K(19456K), 0.0056954 secs] [Times: user=0.02 sys=0.00, real=0.02 secs]
    [GC[DefNew: 5339K->0K(9216K), 0.0052367 secs] 7538K->7114K(19456K), 0.0052673 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
    Heap
    def new generation total 9216K, used 4186K [0x00000000f9a00000, 0x00000000fa400000, 0x00000000fa400000)
    eden space 8192K, 51% used [0x00000000f9a00000, 0x00000000f9e16778, 0x00000000fa200000)
    from space 1024K, 0% used [0x00000000fa200000, 0x00000000fa200088, 0x00000000fa300000)
    to space 1024K, 0% used [0x00000000fa300000, 0x00000000fa300000, 0x00000000fa400000)
    tenured generation total 10240K, used 7113K [0x00000000fa400000, 0x00000000fae00000, 0x00000000fae00000)
    the space 10240K, 69% used [0x00000000fa400000, 0x00000000faaf27c8, 0x00000000faaf2800, 0x00000000fae00000)
    compacting perm gen total 21248K, used 4840K [0x00000000fae00000, 0x00000000fc2c0000, 0x0000000100000000)
    the space 21248K, 22% used [0x00000000fae00000, 0x00000000fb2ba140, 0x00000000fb2ba200, 0x00000000fc2c0000)
    No shared spaces configured.:blush:

本文标题:发生YGC时的一些细节

本文链接:https://www.haomeiwen.com/subject/gitnuxtx.html