码迷,mamicode.com
首页 > 其他好文 > 详细

内存分配分析详解

时间:2016-03-09 23:48:14      阅读:195      评论:0      收藏:0      [点我收藏+]

标签:

先直接看代码吧

package jvm.part_3;
/**
 * VM参数 :-verbose:gc -Xms20M -Xmx20M -Xmn10M -XX:+PrintGCDetails 
 * -XX:SurvivorRatio=8
 * @author foolishbird_lmy
 *
 */
public class TestEden {
	private static final int _1MB = 1024*1024;
	
	public static void main(String[] args) {
		byte[] a1,a2,a3,a4;
		a1 = new byte[2*_1MB];
		a2 = new byte[2*_1MB];
		a3 = new byte[2*_1MB];
		a4 = new byte[4*_1MB];
	}
}

  首先看设置的虚拟机的参数:-Xms20M -Xmx20M 代表设置Java堆的大小为20MB不可扩展;-Xmn10M 代表分配给新生代区域10MB,则剩下的10MB就是老年代区域;-XX:+PrintGCDetails 是告诉虚拟机在发生垃圾收集时打印内存的回收情况,并且在进程退出的时候输出当前的内存各区域分配情况; -XX:SurvivorRatio=8 这是一个虚拟机参数,设定了新生代中Eden区与Survivor区的空间比为8:1;之前学习到垃圾回收的复制算法,就是将堆内存分为一个Eden区与两个Surivor区,分配内存时先分配到Eden区与S区,其中一块S区保留,当执行垃圾回收时,会先将E与S区中的存活对象全部复制到那块保留的S区上,然后统一回收掉,这样的好处是回收的内存不存在碎片;

  但是有一个问题是,如果要回收的内存非常大,但是保留的S区域内存空间不足时,这就涉及到分配担保的问题,后面根据实际代码分析这个问题;

  下面直接看代码运行的日志:

  

[GC[DefNew: 6800K->454K(9216K), 0.0043097 secs] 6800K->6598K(19456K), 0.0043602
secs] [Times: user=0.00 sys=0.00, real=0.01 secs]
Heap
def new generation total 9216K, used 5042K [0x03940000, 0x04340000, 0x0434000
0)
eden space 8192K, 56% used [0x03940000, 0x03dbaf78, 0x04140000)
from space 1024K, 44% used [0x04240000, 0x042b19a8, 0x04340000)
to space 1024K, 0% used [0x04140000, 0x04140000, 0x04240000)
tenured generation total 10240K, used 6144K [0x04340000, 0x04d40000, 0x04d400
00)
the space 10240K, 60% used [0x04340000, 0x04940030, 0x04940200, 0x04d40000)
compacting perm gen total 12288K, used 1601K [0x04d40000, 0x05940000, 0x08d400
00)
the space 12288K, 13% used [0x04d40000, 0x04ed0440, 0x04ed0600, 0x05940000)
No shared spaces configured.

 分析内存日志:

  6800K->454K(9216K) 9216K代表当前内存区域的总容量,当前的内存区域是一个E和一个S,另外一个S区域是保留的,刚才我们已经设定总的新生代内存容量为10MB,E:S=8:1,所以总容量应该就是9M = 9216K;

  继续分析,前三个数组对象每一个都分配2MB内存空间,总共6MB=6144K这个是没有问题的,因为E的空间为8MB足够分配。而6800K->454K 这个6800K就是该区域中内存使用量,包含了3个对象的6144K空间,而多出来的656K估计是其他虚拟机运行时自带占用。之后到第4个数组对象到来了,对象大小为4MB,先到新生代的E区,显而易见现在E区根本没有足够的内存分配给它,这时候就发生了Minor GC也就是新生代的垃圾收集动作,而这个时候就要进行我们之前就说的复制算法,虚拟机是先将E和S中存活的对象都复制到保留的那块S上,然后进行统一回收。麻烦来了,麻烦就是现在S内存区域容量只有1MB,无法存放这些对象,这时候就只能进行分配担保机制,直接一次性将这些存活的对象丢到老年代保存。

  分配担保机制就像是一个保护机制,因为新生代中的对象98%都是朝生夕死的,对象的死亡回收非常频繁,所以很少出现有大量对象存活需要复制到S区域情况,一旦出现这种情况,虚拟机就可以为我们的对象作出一个担保,这些个大对象绝对是好的对象,不是有问题的,不用去S中坐牢等待了,直接去老年代养老吧,如果没什么调用它发挥它预热,之后就可以去死了被回收掉的命运。。

  好了,继续6MB的大对象已经直接被我们丢到了老年代去了,tenured generation total 10240K, used 6144K  老年代总共10MB,现在被用去了6MB,完全一致。然后就可以在新生代进行对象回收了,好吧,你们这些对象都可以去死了,咔嚓以下,瞬间6800K->454K变成454K了,很明显被回收掉了。再看看这个6800K->6598K(19456K),一看不对啊,回收了完全没减少了,看清楚,这个19456=19MB是指的整个堆内存大小,这里为什么是19MB了?新生代E为8MB,两个S为2MB,老年代分配了10MB,只能解释那个保留的S区域不算在内!!

  继续看这个6800K->6598K(19456K),由于3个数组对象直接从E新生代丢到了老年代,导致堆内存总量还是不变,垃圾收集基本没有什么回收对象,相当于地白扫了,小伙伴只是把垃圾从房间丢到了阳台藏起来了,宿管检查不到,但是垃圾还是在宿舍,然并卵!

  好了,现在E区域已经清空了,8MB的内存,装你丫的4MB小家伙绰绰有余了,进来吧!!

  还有一些分析以后补上。。。待续

内存分配分析详解

标签:

原文地址:http://www.cnblogs.com/lmy-foolishbird/p/5259692.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!