这是 HBase 的 GC log。
遗憾由于没有加 -XX:+PrintHeapAtGC 参数,日志只有这些。
暴露的问题:
YGC 时间久,需要 3 至 5 秒,与出现问题之前的 20ms 有很大差距。
JVM 配置如下:
堆大小 30G。
年轻代 3G,SurvivorRatio = 2,E 和 S 的大小分别为 1.5G 和 0.75G。
从日志中可以推断出,应该是 survivor 区空间少,导致存活对象超出 Desired survivor size = 0.75G * 50% = 402653184b,晋升阈值调整为 1,对象过早进入老年代导致。
图中第一次 YGC 的时间为 20ms,比较正常。加了 PrintTenuringDistribution 参数,看到对象分布。
从很多文章中写到,PrintTenuringDistribution 打印的是 survivor 区的对象分布。
但日志中看到 812976448 total,约等于 775M,大于 survivor 区的 768M。
所以我将这个统计理解成希望进入 survivor to 区的对象分布?
第一次正常 YGC 时,单是年龄为 1 的对象就超过了 survivor 区的大小。
所以 YGC 之后,survivor 区被年龄为 1 的对象填满,并且由于 survivor 区的占比超过了 50%,晋升阈值被调整为 1。在之后的 YGC 中,非新分配对象直接晋升到老年代。
在之后的 YGC 中,可以看到,每次 GC 之后,年轻代占用的内存均为 786432K = 0.75G,恰好为一个 survivor 区的大小。
认为之后新分配的存活对象在 YGC 后,占满了 survivor to 区。
但如果将 PrintTenuringDistribution 分布理解成期望进入 survivor 区的对象分布。
但是第一次异常 YGC 发生时,对象总数只用 773677304b 约等于 738M,不足以填满 survivor 区的 768M。
很是疑惑,求指点。