您的位置:首页 > 其它

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

2017-01-07 16:29 330 查看
/**

*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
4000
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.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: