详细分析一下MaxTenuringThreshold在虚拟机垃圾回收中作用及内存分配过程


/**
*VM Args:-verbose:gc -Xms20M -Xmx20M -Xmn10M -XX:+PrintTenuringDistribution -XX:SurvivorRatio=8 
*-XX:+UseParNewGC -XX:MaxTenuringTheshold=1
*/ //以上注释配置了20M堆内存,新生代10M,其中eden8M、survivor或者说from space和to space都是1M。
public class Test
{
private static final int _1MB=1024*1024;
public static void testTenuringThreshold(){
byte[] allocation1,allocation2,allocation3;
allocation1=new byte[_1MB/4];//eden上分配1/4M内存
//什么时候进入老年代取决于XX:MaxTenuringThreshold设置
allocation2=new byte[4*_1MB];//eden上分配4M内存
allocation3=new byte[4*_1MB];//打算在eden上分配4M,但是eden只有8M,一共8+1/4无法分配了(这里eden加上from space是有9M的,但是看下面的GC日志确实发生了GC,猜测大概是eden与survivor不连续,无法提供连续的4M空间吧,这点希望大神指正),引发minorGC(回收时发现对象1、2都还有用,想要复制到to space,但1M的survicor放不下4.25M数据,只可以放下第一个0.25M的,所以结果是0.25从from space转移到了to space,而2的4M数据直接通过分配担保机制进入了老年代),GC之后呢把对象3的4M数据放入了eden。
allocation3=null;//这里对象3取消了引用,但应该还是没有调动GC的
allocation3=new byte[4*_1MB];//这里又即将分配4M内存,之前eden里有可以回收的4M,加一起共8M,而本身eden中应该有一小部分内存占用,大概几百k,所以还是同样的问题,即可能没有足够的连续4M内存用来分配(这里测试如果将对象3后非配内存改为3M,是不会发生GC的),所以引发第二次MinorGC(这次回收中因为之前的4M已没了引用,可以回收,加上tospace中的1/4M的内存已经经过了两次GC,我们设置的年龄最大阀值是1,所以这部分可以晋升为老年代中,故新生代中原内存4.25M全部清零),最后将新的对象3的4M数据放到eden中。
}
public static void main(String[] args){
Test.testTenuringThreshold();
}

}


[GC[DefNew //表示新生代发生GC
Desired survivor size 524288 bytes, new threshold 1 (max 1)//desired survivor size 表示一个survivor大小的一半,也就是1M的一半0.5M
- age   1:     748784 bytes,     748784 total
: 5188K->731K(9216K), 0.0049848 secs] 5188K->4827K(19456K), 0.0054757 secs] [Times: user=0.02 sys=0.00, real=0.01 secs]//5188->731就表示4M去了老年代分配担保,留下1/4M的数据转到了tospace
[GC[DefNew//第二次新生代GC
Desired survivor size 524288 bytes, new threshold 1 (max 1)
- age   1:        136 bytes,        136 total
: 4911K->0K(9216K), 0.0018743 secs] 9007K->4825K(19456K), 0.0020440 secs] [Times//4911->0表示4M无指引的内存被回收,而1/4M的tospace内存因为MaxTenuringThreshold=1所以经过两次GC转为了老年代数据
: user=0.00 sys=0.00, real=0.00 secs]
Heap
 def new generation   total 9216K, used 4260K [0x00000000f9a00000, 0x00000000fa4//最终新生代只剩下了新对象3的4M内存
00000, 0x00000000fa400000)
  eden space 8192K,  52% used [0x00000000f9a00000, 0x00000000f9e28fd0, 0x0000000//最终新生代只剩下了新对象3的4M内存
0fa200000)
  from space 1024K,   0% used [0x00000000fa200000, 0x00000000fa200088, 0x0000000
0fa300000)
  to   space 1024K,   0% used [0x00000000fa300000, 0x00000000fa300000, 0x0000000
0fa400000)
 tenured generation   total 10240K, used 4825K [0x00000000fa400000, 0x00000000fa//老年代存了分配担保机制来的4M和年龄晋升来的1/4M数据,共4824K
e00000, 0x00000000fae00000)
   the space 10240K,  47% used [0x00000000fa400000, 0x00000000fa8b6730, 0x000000
00fa8b6800, 0x00000000fae00000)
 compacting perm gen  total 21248K, used 2702K [0x00000000fae00000, 0x00000000fc
2c0000, 0x0000000100000000)
   the space 21248K,  12% used [0x00000000fae00000, 0x00000000fb0a3be0, 0x000000
00fb0a3c00, 0x00000000fc2c0000)
No shared spaces configured.



接下来,当MaxTenuringThreshold=15时:为了看清survivor起初有多大的空间被占用,我将allocation1注释掉

// allocation1=new byte[_1MB/4];
allocation2=new byte[4*_1MB];
allocation3=new byte[4*_1MB];
allocation3=null;
allocation3=new byte[4*_1MB];

得到[GC[DefNew
Desired survivor size 524288 bytes, new threshold 15 (max 15)
- age   1:     486624 bytes,     486624 total
: 4932K->475K(9216K), 0.0042339 secs] 4932K->4571K(19456K), 0.0047175 secs] [Tim//4932减少到475,也就是初始不分配任何东西进去也被占用了475K
es: user=0.00 sys=0.00, real=0.00 secs]
[GC[DefNew
Desired survivor size 524288 bytes, new threshold 15 (max 15)
- age   1:        136 bytes,        136 total
- age   2:     485136 bytes,     485272 total
: 4655K->473K(9216K), 0.0020539 secs] 8751K->4569K(19456K), 0.0023532 secs] [Tim//这里4655减少到473,可见两次GC之后survivor中数据并没有到老年代去
es: user=0.00 sys=0.00, real=0.00 secs]


这里我再将allocation1分配37K的内存,也就是将上述分配第一行改为allocation1=new byte[37*1024];

得到:[GC[DefNew
Desired survivor size 524288 bytes, new threshold 1 (max 15)
- age   1:     524528 bytes,     524528 total
: 4969K->512K(9216K), 0.0039282 secs] 4969K->4608K(19456K), 0.0042211 secs] [Tim//这里4969减少到512K
es: user=0.00 sys=0.00, real=0.00 secs]
[GC[DefNew
Desired survivor size 524288 bytes, new threshold 15 (max 15)
: 4608K->0K(9216K), 0.0019568 secs] 8704K->4608K(19456K), 0.0024216 secs] [Times//这里4608减少到0,也就是说survivor中数据去了老年代,但是设置了MaxTenuringThreshold=15,本要经过15次GC,这里要提到刚才设置的allocation1的37K数据,37+475=512,而512K数据正好是survivor的一半,这里是根据动态对象年龄判断规则(如果在survivor空间中相同年龄所有对象大小的总和大于survivor空间的一半,年龄大于或等于该年龄的对象就可以直接进入老年代,无须等到MaxTenuringThreshold中要求的年龄)。所以这里第一次GC37K数据从eden区复制到了survivor,加上本身survivor的475K一共512K,在第二次GC的时候这512K数据符合规则直接去了老年代。
: user=0.00 sys=0.00, real=0.00 secs]
Heap
 def new generation   total 9216K, used 4262K [0x00000000f9a00000, 0x00000000fa4
00000, 0x00000000fa400000)
  eden space 8192K,  52% used [0x00000000f9a00000, 0x00000000f9e29b00, 0x0000000
0fa200000)
  from space 1024K,   0% used [0x00000000fa200000, 0x00000000fa200000, 0x0000000
0fa300000)
  to   space 1024K,   0% used [0x00000000fa300000, 0x00000000fa300000, 0x0000000//由对内存数据也可以看出survivor数据去变为了0
0fa400000)
 tenured generation   total 10240K, used 4608K [0x00000000fa400000, 0x00000000fa//老年代数据区存放了分配担保机制过来的4M和512K的数据
e00000, 0x00000000fae00000)
   the space 10240K,  45% used [0x00000000fa400000, 0x00000000fa880100, 0x000000
00fa880200, 0x00000000fae00000)
 compacting perm gen  total 21248K, used 2702K [0x00000000fae00000, 0x00000000fc
2c0000, 0x0000000100000000)
   the space 21248K,  12% used [0x00000000fae00000, 0x00000000fb0a3be0, 0x000000
00fb0a3c00, 0x00000000fc2c0000)
No shared spaces configured.

智能推荐

注意!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系我们删除。



 
© 2014-2019 ITdaan.com 粤ICP备14056181号  

赞助商广告