关于JVM GC回收的疑问

时间:2021-01-18 17:18:21
最近在读关于GC问题看到个例子,这么做都没办法做出应有的效果:
       private static final int _1MB = 1024 * 1024;

public static void main(String[] args) {
testAllocation();
// testPretenureSizeThreshold();
}

/**
 * -verbose:gc -Xms20M -Xmx20M -Xmn10M -XX:+PrintGCDetails -XX:SurvivorRatio=8 
 */
public static void testAllocation() {
byte[] allocation1, allocation2, allocation3, allocation4;
allocation1 = new byte[2 * _1MB];
allocation2 = new byte[2 * _1MB];
allocation3 = new byte[2 * _1MB];
allocation4 = new byte[5 * _1MB];
}

        /**
 * -verbose:gc -Xms20M -Xmx20M -Xmn10M -XX:+PrintGCDetails -XX:SurvivorRatio=8 -XX:PretenureSizeThreshold=3145728
 */
public static void testPretenureSizeThreshold() {
byte[] allocation;
allocation = new byte[4 * _1MB];
}


1)在文章上是这样说的,testAllocation()在执行到allocation4 = new byte[5 * _1MB];的时候会超出新生代,导致产生一次minor GC,可是我在打印GC信息的过程中并没有发生GC,下面是我打印的结果:

Heap
 PSYoungGen      total 9216K, used 6979K [0x00000000ff600000, 0x0000000100000000, 0x0000000100000000)
  eden space 8192K, 85% used [0x00000000ff600000,0x00000000ffcd0fa0,0x00000000ffe00000)
  from space 1024K, 0% used [0x00000000fff00000,0x00000000fff00000,0x0000000100000000)
  to   space 1024K, 0% used [0x00000000ffe00000,0x00000000ffe00000,0x00000000fff00000)
 ParOldGen       total 10240K, used 5120K [0x00000000fec00000, 0x00000000ff600000, 0x00000000ff600000)
  object space 10240K, 50% used [0x00000000fec00000,0x00000000ff100010,0x00000000ff600000)
 PSPermGen       total 21504K, used 2483K [0x00000000f9a00000, 0x00000000faf00000, 0x00000000fec00000)
  object space 21504K, 11% used [0x00000000f9a00000,0x00000000f9c6cd80,0x00000000faf00000)
感觉allocation4 = new byte[5 * _1MB];直接进入了年老代,有点迷茫

2)执行testPretenureSizeThreshold方法的时候,我已经指定了XX:PretenureSizeThreshold=3145728,也就是说当我开创allocation = new byte[4 * _1MB]; 一个大于3MB的空间时候,应该直接进入年老代,但是打印结果却是:

Heap
 PSYoungGen      total 9216K, used 4931K [0x00000000ff600000, 0x0000000100000000, 0x0000000100000000)
  eden space 8192K, 60% used [0x00000000ff600000,0x00000000ffad0f80,0x00000000ffe00000)
  from space 1024K, 0% used [0x00000000fff00000,0x00000000fff00000,0x0000000100000000)
  to   space 1024K, 0% used [0x00000000ffe00000,0x00000000ffe00000,0x00000000fff00000)
 ParOldGen       total 10240K, used 0K [0x00000000fec00000, 0x00000000ff600000, 0x00000000ff600000)
  object space 10240K, 0% used [0x00000000fec00000,0x00000000fec00000,0x00000000ff600000)
 PSPermGen       total 21504K, used 2483K [0x00000000f9a00000, 0x00000000faf00000, 0x00000000fec00000)
  object space 21504K, 11% used [0x00000000f9a00000,0x00000000f9c6cd80,0x00000000faf00000)
从打印上看,并没有进入到年老代。

请大神指导,我用的JDK是1.7.0.51,eclipse下编译。

5 个解决方案

#1


你确定在Eclipse下正确设置了VM参数没有?我试了没问题啊,虽然我用的是JDK8下的1.7环境,但JDK7也不应该有问题啊

第一个测试
[GC (Allocation Failure) [DefNew: 6809K->464K(9216K), 0.0042200 secs] 6809K->6608K(19456K), 0.0042709 secs] [Times: user=0.00 sys=0.00, real=0.01 secs] 
Heap
 def new generation   total 9216K, used 5912K [0x03a00000, 0x04400000, 0x04400000)
  eden space 8192K,  66% used [0x03a00000, 0x03f520a0, 0x04200000)
  from space 1024K,  45% used [0x04300000, 0x043741d8, 0x04400000)
  to   space 1024K,   0% used [0x04200000, 0x04200000, 0x04300000)
 tenured generation   total 10240K, used 6144K [0x04400000, 0x04e00000, 0x04e00000)
   the space 10240K,  60% used [0x04400000, 0x04a00030, 0x04a00200, 0x04e00000)
 Metaspace       used 79K, capacity 2242K, committed 2368K, reserved 4480K

第二个测试
Heap
 def new generation   total 9216K, used 829K [0x03800000, 0x04200000, 0x04200000)
  eden space 8192K,  10% used [0x03800000, 0x038cf5a8, 0x04000000)
  from space 1024K,   0% used [0x04000000, 0x04000000, 0x04100000)
  to   space 1024K,   0% used [0x04100000, 0x04100000, 0x04200000)
 tenured generation   total 10240K, used 4096K [0x04200000, 0x04c00000, 0x04c00000)
   the space 10240K,  40% used [0x04200000, 0x04600010, 0x04600200, 0x04c00000)
 Metaspace       used 79K, capacity 2242K, committed 2368K, reserved 4480K

#2


你肯定把两个测试的参数弄反了。。我反过来试了一下和你的结果一样

#3


我确定没有将参数弄反,但是现在我可以得到正确答案了,但是我加上了-verbose:gc -Xms20M -Xmx20M -Xmn10M -XX:+PrintGCDetails -XX:SurvivorRatio=8 -XX: +UseSerialGC 
我想问下+UseSerialGC加上这个串行化就可以得到正确答案?那本身默认的是什么?我看还有2种是并行和并发,那默认的是哪一种,为什么其他的就得不到正确的结果呢

#4


原来不同机器默认GC还不同 关于JVM GC回收的疑问
我换了一台多核CPU的电脑发现和你一样,默认是Parallel Scavenge GC,而单核机器上默认是Serial GC

这个PS GC确实比较奇葩,Serial GC和ParNew GC都没问题,但PS GC好像无视PretenureSizeThreshold这个参数,而且当Eden区放不下的时候,是马上进行Minor GC还是直接放入Tenured区也不是确定的,要根据Eden区有多满以及新创建的数据有多大来决定

我翻了各种资料,中文英文搜索搜了半天,也没找到一篇讲PS GC具体工作机制的文章,几乎全是概念性的泛泛而谈毫无价值,所以也不太清楚PS GC到底是什么策略

#5


看来还是得多看下资料,虽然还是不明白,但是非常感谢你了。这一块的东西有的好恶补了,不是一个帖子能解决的。十分感谢。

#1


你确定在Eclipse下正确设置了VM参数没有?我试了没问题啊,虽然我用的是JDK8下的1.7环境,但JDK7也不应该有问题啊

第一个测试
[GC (Allocation Failure) [DefNew: 6809K->464K(9216K), 0.0042200 secs] 6809K->6608K(19456K), 0.0042709 secs] [Times: user=0.00 sys=0.00, real=0.01 secs] 
Heap
 def new generation   total 9216K, used 5912K [0x03a00000, 0x04400000, 0x04400000)
  eden space 8192K,  66% used [0x03a00000, 0x03f520a0, 0x04200000)
  from space 1024K,  45% used [0x04300000, 0x043741d8, 0x04400000)
  to   space 1024K,   0% used [0x04200000, 0x04200000, 0x04300000)
 tenured generation   total 10240K, used 6144K [0x04400000, 0x04e00000, 0x04e00000)
   the space 10240K,  60% used [0x04400000, 0x04a00030, 0x04a00200, 0x04e00000)
 Metaspace       used 79K, capacity 2242K, committed 2368K, reserved 4480K

第二个测试
Heap
 def new generation   total 9216K, used 829K [0x03800000, 0x04200000, 0x04200000)
  eden space 8192K,  10% used [0x03800000, 0x038cf5a8, 0x04000000)
  from space 1024K,   0% used [0x04000000, 0x04000000, 0x04100000)
  to   space 1024K,   0% used [0x04100000, 0x04100000, 0x04200000)
 tenured generation   total 10240K, used 4096K [0x04200000, 0x04c00000, 0x04c00000)
   the space 10240K,  40% used [0x04200000, 0x04600010, 0x04600200, 0x04c00000)
 Metaspace       used 79K, capacity 2242K, committed 2368K, reserved 4480K

#2


你肯定把两个测试的参数弄反了。。我反过来试了一下和你的结果一样

#3


我确定没有将参数弄反,但是现在我可以得到正确答案了,但是我加上了-verbose:gc -Xms20M -Xmx20M -Xmn10M -XX:+PrintGCDetails -XX:SurvivorRatio=8 -XX: +UseSerialGC 
我想问下+UseSerialGC加上这个串行化就可以得到正确答案?那本身默认的是什么?我看还有2种是并行和并发,那默认的是哪一种,为什么其他的就得不到正确的结果呢

#4


原来不同机器默认GC还不同 关于JVM GC回收的疑问
我换了一台多核CPU的电脑发现和你一样,默认是Parallel Scavenge GC,而单核机器上默认是Serial GC

这个PS GC确实比较奇葩,Serial GC和ParNew GC都没问题,但PS GC好像无视PretenureSizeThreshold这个参数,而且当Eden区放不下的时候,是马上进行Minor GC还是直接放入Tenured区也不是确定的,要根据Eden区有多满以及新创建的数据有多大来决定

我翻了各种资料,中文英文搜索搜了半天,也没找到一篇讲PS GC具体工作机制的文章,几乎全是概念性的泛泛而谈毫无价值,所以也不太清楚PS GC到底是什么策略

#5


看来还是得多看下资料,虽然还是不明白,但是非常感谢你了。这一块的东西有的好恶补了,不是一个帖子能解决的。十分感谢。