对象主要分配在Eden区上,如果启动了本地线程分配缓冲,将按线程优先在TLAB上分配(TLAB是在堆中为每个线程临时开辟一块内存区域用作内存分配)。少数情况下也可能会直接分配在老年代中,分配的规则并不是百分之百固定的,其细节取决于当前使用的是哪一种垃圾收集器组合,还有虚拟机中与内存有关的配置。
接下来会讲解几条最普遍的内存分配规则,验证使用的是Serial/SerialOld收集器下的内存分配与回收策略,ParNew/Serial Old组合的规则也基本一致。
假设新生代中 Eden:Survivor(from space):Survivor(to space) = 8:1:1 , 新生代的可用内存实际为新生代总内存的的9/10。
- 对象优先在Eden分配,当Eden没有足够空间并且from space也没有足够内存分配给对象时,将发生一次Minor GC;发生Minor GC时,如果to space的内存大小无法放下新生代中存活的对象,则这些对象将会通过空间分配担保措施提前进入老年代。
- 大对象直接进入老年代,例如那种很长的字符串或数组就是大对象,尽量避免写那种朝生夕灭的大对象。为了避免Eden和Survivor区之间发生频繁的内存复制,jvm提供了一个-XX:PretenureSizeThreshold参数,令大于这个设置值的对象直接在老年代分配。
- 长期存活的对象将进入老年代
- 动态对象年龄判定
- 空间分配担保
在进行Minor GC之前,jvm会先检查老年代的最大可用连续空间是否大于新生代对象总大小或新生代历次晋升到老年代的对象大小平均值,如果大于,则进行一次Minor GC, 否则将进行Full GC,回收老年代的内存。
如果Minor GC失败,也会进行一次Full GC。
什么是Minor GC 和 Full GC