淘先锋技术网

首页 1 2 3 4 5 6 7

上一篇博文讲述了Java内存回收策略,这一次我们讲述一下Java内存分配策略。
这里我们先假设一个模型,我们假设:新生代总内存是10MB,其中Eden区与Survivor区的内存占比是8:1,也就是Eden区是8MB,而Survivor区是1MB;老年代总内存也设为10MB;
分配原则是:
1.优先分配在Eden区
也就是说大多数情况下,对象在Eden区中分配。
这里有一个问题是,如果我们要分配一个大对象,比如8MB的对象,是否直接分配于Eden区吗(占比100%)?
答案是否定的,因为我们知道,Eden区内存不足的时候,会执行一次Minor GC,采用复制算法将Eden区原有的对象置于两个Servivor区,为了避免Eden于Servivor区大量的内存复制,我们直接将大对象分配在老年区。
可能有一个疑问是,大小是多少的对象是大对象?
这个大小是我们自己根据实际情况设定的。
2.如果Eden区内存不足,对象将分配在Servivor区或者老年区
我们知道,Eden区内存不足的时候,会执行一次Minor GC,采用复制算法将Eden区的原有的对象置于两个Servivor区,但是这里有个问题,Servivor区有足够的空间放置下原有的对象吗?
这里是这样分配的,当Servivor区有足够的空间放置原有的对象时,那么Minor GC后原有的对象就放置在Servivor区。
而Servivor区没有足够的内存放置原有的对象时,那么将原有的对象放置于老年区。
3.长期存活的对象将进入老年代
当虚拟机发生Minor GC后,在原有的对象仍然存活,并能被Servivor区容纳的情况下,原有的对象将被复制在Servivor区,这时,虚拟机将这些对象的对象年龄计数器加一。而且对象在Servivor区如果每经历过一次Minor GC,它的对象年龄计数器就加一。
这里我们可以设定一个阈值,当对象的年龄超过这个值后,它就晋升到老年代中。默认是15.
4.老年区分配担保机制
在Minor GC的后,对象分配一般就两种情况,有时候对象分配在Servivor区,有时候分配在老年区,这里有一个问题是,由于Minor GC后才能确定分配到老年区的对象大小,那么,老年区是否有足够的连续空间放置分配的对象?
因此在Minor GC之前,虚拟机会先检查老年代最大可用的连续空间是否大于新生代所有对象的总空间,如果大于,那么Minor GC可以确保安全。如果小于,则虚拟机会查看是否允许担保失败
如果允许担保失败,那么会继续检查老年代最大可用的连续空间是否大于历次晋升到老年代对象的平均大小,如果大于,将尝试进行一次Minor GC,尽管这次Minor GC是有风险的;如果小于,或者不允许担保失败,那这时要进行一次Full
GC。
那么在有风险的情况下进行Minor GC后,如果老年区没有足够的连续空间放置分配的对象,那么只能进行一次Full GC了,Full GC采取的方法一般是标记-清除或者标记-整理算法。
这里可能有人会问,为什么要在老年区采用分配担保机制?完全可以每次Minor GC前进行一次Full GC啊,也就不用分配担保机制了。
这是因为Full GC是一个比较消耗计算机资源的行为,Full GC的速度比Minor GC的速度慢十倍以上,因此应该尽量避免Full GC,