Java堆内存的分配
堆可以细分为:新生代和老年代;其中新生代可以进一步分为Eden空间、From Survivor空间、To Survivor空间。
分代回收
Java采用分代回收的方式进行垃圾回收,新生代主要采用复制算法,老年代采用标记-清除、标记-整理算法:
首先,一般的对象产生都会在Eden中,较大的对象会直接进入老年代这个由参数 -XX:PretenureSizeThreshold设置。在新生代中三个区域eden,from,to,一个时刻只会有两片内存被使用,首先eden肯定会被使用,from和to只有一片会被使用,主要是由于虚拟机采用的复制算法。
- minor gc:为了避免在gc的时候产生内存碎片,jvm以牺牲空间的方式来做的,首先eden空间不足时会产生一次minor gc,垃圾回收器会在eden和一片使用的Survivor(假设是from)中进行清理,存活下来的对象会被复制到to中(假设to的大小足够装满),然后清空eden和from,保留下来的对象年龄加一。当年龄到达某一个设定值时会进入老年代,默认是15岁,由参数-XX:MaxTenuringThreshold设置。还有一种情况是在Survivor区域中相同年龄所有对象大小的总和,大于Survivor区域一半时,所有该年龄及以上的都会被移动到老年代。
- full gc:minor gc时Survivor区域不足以容纳年轻代中存活下来的对象时,且老年代中剩余空间容纳不了新生代中存活下来的对象时会进行full gc。老年代中因为没有进行分区,所以回收算法使用的是标记-清理算法或者标记整理算法。
新生代两个Survivor区原因:新生代采用复制算法,如果只有一个Survivor区,那么当进行Minor Gc时,可能会产生碎片。
触发full gc条件:
1、System.gc()方法的调用
2、老年代代空间不足
3、永生区空间不足
4、CMS GC时出现promotion failed和concurrent mode failure
5、统计得到的Minor GC晋升到旧生代的平均大小大于老年代的剩余空间
6、堆中分配很大的对象