深入理解java虚拟机-3 内存分配与回收策略

Java技术体系中的自动化内存管理最终可以分为两个问题:给对象分配内存以及回收分配给对象的内存

下面使用Serial 和serial Old收集器来验证分配策略

1,对象优先在Eden分配

新生区分 Eden与Serivivor 默认比例8:1
大多数情况下,对象在新生代Eden中分配,新生代没有空间时,虚拟机发起一场Minor GC
-XX:+PrintfGCDetails 在垃圾回收时打印内存回收日志.

-XX:+UseSerialGC
Jvm运行在Client模式下的默认值,打开此开关后,使用Serial + Serial Old的收集器组合进行内存回收
-XX:+UseParNewGC 打开此开关后,使用ParNew + Serial Old的收集器进行垃圾回收
-XX:+UseConcMarkSweepGC 使用ParNew + CMS +  Serial Old的收集器组合进行内存回收,Serial Old作为CMS出现“Concurrent Mode Failure”失败后的后备收集器使用。
下面通过一个实验验证新生代分配.在Client模式下

package day20150803;


public class JVMEdenTest {
	
	public static void main(String[] args) {
		JVMEdenTest edenTest = new JVMEdenTest();
		edenTest.eden();
	}
	private static final int _1M = 1024*1024;
	
	/**
	 * -verbose:gc -Xms20M -Xmx20M -Xmn10M -XX:+PrintGCDetails -XX:SurvivorRatio=8 -XX:+UseSerialGC
	 */
	public void eden(){
		byte[] a1,a2,a3,a4;
		a1 = new byte[2* this._1M];
		System.out.println(1);
		a2 = new byte[2* this._1M];
		System.out.println(2);
		a3 = new byte[2* this._1M];
		System.out.println(3);
		a4 = new byte[4* this._1M];
		System.out.println(4);
		System.gc();
	}
}

使用Serial/Serial Old的运行结果如下
1
2
3
[GC [DefNew: 6487K->200K(9216K), 0.0041264 secs] 6487K->6344K(19456K), 0.0041617 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
4
[Full GC (System) [Tenured: 6144K->6144K(10240K), 0.0038670 secs] 10526K->10440K(19456K), [Perm : 2975K->2975K(21248K)], 0.0039080 secs] [Times: user=0.01 sys=0.00, real=0.00 secs] 
Heap
 def new generation   total 9216K, used 4460K [0x00000000054c0000, 0x0000000005ec0000, 0x0000000005ec0000)
  eden space 8192K,  54% used [0x00000000054c0000, 0x000000000591b230, 0x0000000005cc0000)
  from space 1024K,   0% used [0x0000000005dc0000, 0x0000000005dc0000, 0x0000000005ec0000)
  to   space 1024K,   0% used [0x0000000005cc0000, 0x0000000005cc0000, 0x0000000005dc0000)
 tenured generation   total 10240K, used 6144K [0x0000000005ec0000, 0x00000000068c0000, 0x00000000068c0000)
   the space 10240K,  60% used [0x0000000005ec0000, 0x00000000064c0048, 0x00000000064c0200, 0x00000000068c0000)
 compacting perm gen  total 21248K, used 3006K [0x00000000068c0000, 0x0000000007d80000, 0x000000000bcc0000)
   the space 21248K,  14% used [0x00000000068c0000, 0x0000000006bafb68, 0x0000000006bafc00, 0x0000000007d80000)
No shared spaces configured.

使用-XX:+UseParNewGC参数启动,与Serial运行结果类似

1
2
3
[GC [ParNew: 6651K->222K(9216K), 0.0039702 secs] 6651K->6366K(19456K), 0.0040129 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
4
[Full GC (System) [Tenured: 6144K->6144K(10240K), 0.0042741 secs] 10548K->10442K(19456K), [Perm : 3007K->3007K(21248K)], 0.0043094 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
Heap
 par new generation   total 9216K, used 4462K [0x0000000005910000, 0x0000000006310000, 0x0000000006310000)
  eden space 8192K,  54% used [0x0000000005910000, 0x0000000005d6bad0, 0x0000000006110000)
  from space 1024K,   0% used [0x0000000006210000, 0x0000000006210000, 0x0000000006310000)
  to   space 1024K,   0% used [0x0000000006110000, 0x0000000006110000, 0x0000000006210000)
 tenured generation   total 10240K, used 6144K [0x0000000006310000, 0x0000000006d10000, 0x0000000006d10000)
   the space 10240K,  60% used [0x0000000006310000, 0x0000000006910048, 0x0000000006910200, 0x0000000006d10000)
 compacting perm gen  total 21248K, used 3039K [0x0000000006d10000, 0x00000000081d0000, 0x000000000c110000)
   the space 21248K,  14% used [0x0000000006d10000, 0x0000000007007f00, 0x0000000007008000, 0x00000000081d0000)
No shared spaces configured.

但是使用-XX:+UseConcMarkSweepGC的结果却不一样,他第四次分配内存时,没有进行垃圾收集
我将第四个对象设置为9M的运行结果如下

1
2
3
4
[GC-- [PSYoungGen: 6487K->6487K(9216K)] 15703K->15703K(19456K), 0.0007538 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
[Full GC (System) [PSYoungGen: 6487K->6344K(9216K)] [PSOldGen: 9216K->9216K(10240K)] 15703K->15560K(19456K) [PSPermGen: 2966K->2966K(21248K)], 0.0054435 secs] [Times: user=0.00 sys=0.00, real=0.01 secs] 
Heap
 PSYoungGen      total 9216K, used 6508K [0x000000000b260000, 0x000000000bc60000, 0x000000000bc60000)
  eden space 8192K, 79% used [0x000000000b260000,0x000000000b8bb2e0,0x000000000ba60000)
  from space 1024K, 0% used [0x000000000bb60000,0x000000000bb60000,0x000000000bc60000)
  to   space 1024K, 0% used [0x000000000ba60000,0x000000000ba60000,0x000000000bb60000)
 PSOldGen        total 10240K, used 9216K [0x000000000a860000, 0x000000000b260000, 0x000000000b260000)
  object space 10240K, 90% used [0x000000000a860000,0x000000000b160018,0x000000000b260000)
 PSPermGen       total 21248K, used 3006K [0x0000000005460000, 0x0000000006920000, 0x000000000a860000)
  object space 21248K, 14% used [0x0000000005460000,0x000000000574fb70,0x0000000006920000)

可以发现第四个对象并没有让新生代发生Minor GC 而是直接让其进入老年代

2.大对象直接进入老年代

大内存对象在新生区中占用内存大,容易触发垃圾收集,并且垃圾收集时的内存负责又特别耗时间,所以,让大对象直接进入老年代
-XX:PretrnureSizeThreshold 设置超过制定大小的对象,直接进入老年代.还是使用Serial

老年代为啥9M被使用??
运行参数-verbose:gc -Xms20M -Xmx20M -Xmn10M -XX:+PrintGCDetails -XX:SurvivorRatio=8 -XX:+UseSerialGC -XX:PretenureSizeThreshold=3145728
1
2
3
4
[Full GC (System) [Tenured: 5120K->9419K(10240K), 0.0060684 secs] 11771K->11467K(19456K), [Perm : 2998K->2998K(21248K)], 0.0061260 secs] [Times: user=0.00 sys=0.00, real=0.01 secs] 
Heap
 def new generation   total 9216K, used 2130K [0x0000000005480000, 0x0000000005e80000, 0x0000000005e80000)
  eden space 8192K,  26% used [0x0000000005480000, 0x0000000005694868, 0x0000000005c80000)
  from space 1024K,   0% used [0x0000000005c80000, 0x0000000005c80000, 0x0000000005d80000)
  to   space 1024K,   0% used [0x0000000005d80000, 0x0000000005d80000, 0x0000000005e80000)
 tenured generation   total 10240K, used 9419K [0x0000000005e80000, 0x0000000006880000, 0x0000000006880000)
   the space 10240K,  91% used [0x0000000005e80000, 0x00000000067b2c38, 0x00000000067b2e00, 0x0000000006880000)
 compacting perm gen  total 21248K, used 3039K [0x0000000006880000, 0x0000000007d40000, 0x000000000bc80000)
   the space 21248K,  14% used [0x0000000006880000, 0x0000000006b77e90, 0x0000000006b78000, 0x0000000007d40000)
No shared spaces configured.


3.长期存活进入老年代

每个对象都有一个对象年龄计数器,新生代的对象,没熬过一个Minor就增加一次年龄,到了一定程度就进入老年区(默认15)
-XX:MaxTenuringThreshold

测试代码为:

<pre name="code" class="java">public static void age(){
		byte[] a1,a2,a3,a4;
		a1 = new byte[_1M/4];
		System.out.println(1);
		a2 = new byte[4* _1M];
		System.out.println(2);
		a3 = new byte[4* _1M];
		a3 =null;
		a3 = new byte[4* _1M];
		System.out.println(3);
	}


 应当发生两次垃圾回收 
 

使用下面的参数:
-verbose:gc -Xms20M -Xmx20M -Xmn10M -XX:+PrintGCDetails -XX:SurvivorRatio=8
 -XX:+UseSerialGC  -XX:MaxTenuringThreshold=1 -XX:+PrintTenuringDistribution

结果为:
1
2
[GC [DefNew
Desired survivor size 524288 bytes, new threshold 1 (max 1)
- age   1:     467616 bytes,     467616 total
: 4695K->456K(9216K), 0.0032289 secs] 4695K->4552K(19456K), 0.0032694 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
1
2
[GC [DefNew
Desired survivor size 524288 bytes, new threshold 1 (max 1)
- age   1:     470072 bytes,     470072 total
: 4859K->459K(9216K), 0.0032472 secs] 4859K->4555K(19456K), 0.0033008 secs] [Times: user=0.02 sys=0.00, real=0.00 secs] 
[GC [DefNew
Desired survivor size 524288 bytes, new threshold 1 (max 1)
: 4555K->0K(9216K), 0.0006683 secs] 8651K->4554K(19456K), 0.0007002 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
3
Heap
 def new generation   total 9216K, used 4265K [0x00000000054f0000, 0x0000000005ef0000, 0x0000000005ef0000)
  eden space 8192K,  52% used [0x00000000054f0000, 0x000000000591a648, 0x0000000005cf0000)
  from space 1024K,   0% used [0x0000000005cf0000, 0x0000000005cf0000, 0x0000000005df0000)
  to   space 1024K,   0% used [0x0000000005df0000, 0x0000000005df0000, 0x0000000005ef0000)
 tenured generation   total 10240K, used 4554K [0x0000000005ef0000, 0x00000000068f0000, 0x00000000068f0000)
   the space 10240K,  44% used [0x0000000005ef0000, 0x0000000006362b50, 0x0000000006362c00, 0x00000000068f0000)
 compacting perm gen  total 21248K, used 3039K [0x00000000068f0000, 0x0000000007db0000, 0x000000000bcf0000)
   the space 21248K,  14% used [0x00000000068f0000, 0x0000000006be7fa8, 0x0000000006be8000, 0x0000000007db0000)
No shared spaces configured.

而使用下面的参数
-verbose:gc -Xms20M -Xmx20M -Xmn10M -XX:+PrintGCDetails -XX:SurvivorRatio=8
 -XX:+UseSerialGC  -XX:MaxTenuringThreshold=15 -XX:+PrintTenuringDistribution

结果为:
1
2
[GC [DefNew
Desired survivor size 524288 bytes, new threshold 10 (max 10)
- age   1:     470072 bytes,     470072 total
: 4859K->459K(9216K), 0.0033601 secs] 4859K->4555K(19456K), 0.0033943 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
[GC [DefNew
Desired survivor size 524288 bytes, new threshold 10 (max 10)
- age   2:     470072 bytes,     470072 total
: 4555K->459K(9216K), 0.0007338 secs] 8651K->4555K(19456K), 0.0007623 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
3
Heap
 def new generation   total 9216K, used 4724K [0x0000000005450000, 0x0000000005e50000, 0x0000000005e50000)
  eden space 8192K,  52% used [0x0000000005450000, 0x000000000587a648, 0x0000000005c50000)
  from space 1024K,  44% used [0x0000000005c50000, 0x0000000005cc2c38, 0x0000000005d50000)
  to   space 1024K,   0% used [0x0000000005d50000, 0x0000000005d50000, 0x0000000005e50000)
 tenured generation   total 10240K, used 4096K [0x0000000005e50000, 0x0000000006850000, 0x0000000006850000)
   the space 10240K,  40% used [0x0000000005e50000, 0x0000000006250018, 0x0000000006250200, 0x0000000006850000)
 compacting perm gen  total 21248K, used 3039K [0x0000000006850000, 0x0000000007d10000, 0x000000000bc50000)
   the space 21248K,  14% used [0x0000000006850000, 0x0000000006b47fa8, 0x0000000006b48000, 0x0000000007d10000)

No shared spaces configured.


4.动态年龄判定

并不是到达指定年龄才有机会进入老年区,在Survivor中同年龄的对象大小超过或大于Survivor一般,大于或等于此年龄的直接进入老年代,
使用的参数
-verbose:gc -Xms20M -Xmx20M -Xmn10M -XX:+PrintGCDetails -XX:SurvivorRatio=8
 -XX:+UseSerialGC  -XX:MaxTenuringThreshold=15 -XX:+PrintTenuringDistribution

public static void age(){
		byte[] a1,a2,a3,a4;
		a1 = new byte[_1M/4];
		a4 = new byte[_1M/4];
		System.out.println(1);
		a2 = new byte[4* _1M];
		System.out.println(2);
		a3 = new byte[4* _1M];
		a3 =null;
		a3 = new byte[4* _1M];
		System.out.println(3);
	}
}

1
2
[GC [DefNew
Desired survivor size 524288 bytes, new threshold 1 (max 10)
- age   1:     729784 bytes,     729784 total
: 4951K->712K(9216K), 0.0034507 secs] 4951K->4808K(19456K), 0.0034901 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
[GC [DefNew
Desired survivor size 524288 bytes, new threshold 10 (max 10)
: 4808K->0K(9216K), 0.0009385 secs] 8904K->4808K(19456K), 0.0009744 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
3
Heap
 def new generation   total 9216K, used 4347K [0x0000000005520000, 0x0000000005f20000, 0x0000000005f20000)
  eden space 8192K,  53% used [0x0000000005520000, 0x000000000595ed90, 0x0000000005d20000)
  from space 1024K,   0% used [0x0000000005d20000, 0x0000000005d20000, 0x0000000005e20000)
  to   space 1024K,   0% used [0x0000000005e20000, 0x0000000005e20000, 0x0000000005f20000)
 tenured generation   total 10240K, used 4808K [0x0000000005f20000, 0x0000000006920000, 0x0000000006920000)
   the space 10240K,  46% used [0x0000000005f20000, 0x00000000063d22d0, 0x00000000063d2400, 0x0000000006920000)
 compacting perm gen  total 21248K, used 3007K [0x0000000006920000, 0x0000000007de0000, 0x000000000bd20000)
   the space 21248K,  14% used [0x0000000006920000, 0x0000000006c0fc20, 0x0000000006c0fe00, 0x0000000007de0000)
No shared spaces configured.

a1与a4直接进入到了老年代,因为a1和a4加起来是Servivor的一半,两个一起进入老年代
我们注释掉a4再来看看结果

1
2
[GC [DefNew
Desired survivor size 524288 bytes, new threshold 10 (max 10)
- age   1:     467616 bytes,     467616 total
: 4695K->456K(9216K), 0.0052422 secs] 4695K->4552K(19456K), 0.0052981 secs] [Times: user=0.00 sys=0.00, real=0.01 secs] 
[GC [DefNew
Desired survivor size 524288 bytes, new threshold 10 (max 10)
- age   2:     467360 bytes,     467360 total
: 4552K->456K(9216K), 0.0007019 secs] 8648K->4552K(19456K), 0.0007612 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
3
Heap
 def new generation   total 9216K, used 4804K [0x0000000005460000, 0x0000000005e60000, 0x0000000005e60000)
  eden space 8192K,  53% used [0x0000000005460000, 0x000000000589eec0, 0x0000000005c60000)
  from space 1024K,  44% used [0x0000000005c60000, 0x0000000005cd21a0, 0x0000000005d60000)
  to   space 1024K,   0% used [0x0000000005d60000, 0x0000000005d60000, 0x0000000005e60000)
 tenured generation   total 10240K, used 4096K [0x0000000005e60000, 0x0000000006860000, 0x0000000006860000)
   the space 10240K,  40% used [0x0000000005e60000, 0x0000000006260018, 0x0000000006260200, 0x0000000006860000)
 compacting perm gen  total 21248K, used 3007K [0x0000000006860000, 0x0000000007d20000, 0x000000000bc60000)
   the space 21248K,  14% used [0x0000000006860000, 0x0000000006b4fc10, 0x0000000006b4fe00, 0x0000000007d20000)
No shared spaces configured.

Servivor中还有一个a1,并没有进入老年代.


5.空间分配担保

在发生Minor之前,jvm会先检查老年代的连续空间是否大于新生代所以对象总空间,大于就进行Minor,否则就进行Full GC
在jdj1.6以前.HandlePromotionFailture可以设置是否冒险进行Minor GC,但是1.6之后这个值就不使用了


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值