Java堆是垃圾收集器管理的主要区域。因为基本采用分代收集算法,所以Java堆可以细分为新生代和老年代,更细致是Eden、From Survivor和To Survivor。划分的目的是更好地回收内存或更快地分配内存。根据JVM规范,Java堆可以处于物理上不连续的内存空间中,要求逻辑上连续。
1 对象优先在Eden区中分配
大多数情况下,对象在新生代Eden区中分配。当Eden区没有足够空间分配时,虚拟机发起一次Minor GC。
2 大对象直接进入老年代
大对象指需要大量连续内存空间的Java对象,例如很长的字符串和大数组。大对象对于JVM的内存分配来说是一个坏消息,比遇到一个大对象更坏的消息是遇到一群“朝生夕灭”的“短命大对象”,经常出现大对象容易导致内存还有不少空间时提前触发垃圾收集以获取足够的连续空间来“安置”它们。
3 长期存活的对象将进入老年代
JVM给每个对象定义了一个对象年龄(Age)计数器。如果对象在Eden区分配并经过第一次Minor GC后仍然存活,并且能被Survivor容纳,则将该对象移动到Survivor空间中,对象年龄设为1。对象在Survivor区中每“熬过“一次Minor GC,年龄增加1岁,当年龄增加到一定程度(默认为15岁),晋升到老年代。
新生代GC(Minor GC):因为Java对象大多具备朝生夕灭的特性,所以Minor GC非常频繁,一般回收速度比较快。
老年代GC(Full GC / Major GC):经常会伴随至少一次的Minor GC。Major GC的速度一般会比Minor GC慢10倍以上。
参考资料
《深入理解Java虚拟机 JVM高级特性与最佳实践 第2版》P41 P91-97