内存分配和回收策略

jvm提供的内存管理主要包括内存分配和内存回收,内存分配主要是在堆上分配,jvm将堆区划分为新生代:Eden区,2个survivor区,老年代,创建的对象主要分配在Eden区,也有大对象、长期存活的对象分配到老年代中。对象的分配与垃圾收集器组合以及jvm中设置的参数有关。下面将介绍几种常用的内存分配策略。

1.对象优先在Eden区分配

一般情况下,创建的新对象会直接分配到新生代的Eden区,当Eden区中没有足够存储空间时,jvm会触发一次Minor GC,将Eden区和其中一个survivor区中的存活对象复制到另一个survivor区中,然后清空Eden、from survivor区中的所有对象。如果to survivor区中的内存不够存储从minor gc中存活下来的对象时,通过老年代担保机制,将存活对象直接放入老年代中。

2.大对象直接进入老年代

大对象是指需要大量连续内存空间的java对象,常见的大对象有超长的字符串,字节数组,经常出现大对象导致的后果就是,需要频繁地发生GC来获取更多的连续空间用于存储新生大对象。
在jvm中提供参数用于设定超过此值的对象直接进入老年代,避免在新生代中发生大量内存复制。

3.长期存活的对象进入老年代

jvm将堆空间分为老年代和新生代,新生代中经常要发生minor gc,老年代发生major gc频率较低。如果是长期存活的对象放在新生代中,则会在每次minor gc时产生内存复制,所以对于长期存活的对象应将其移到老年代中。

如何判定一个对象应该是处于新生代还是老年代?
jvm给每个对象都定义了一个对象年龄计数器,当对象第一次经过minor gc进入survivor区后,对象年龄增加1,以后每次minor gc,对象的年龄增加1,当对象年龄增加到设定的最大阈值时,对象从survivor区进入老年代中。

4.动态对象年龄判定

新生代中的对象根据对象年龄判定对象是否能够进入老年代,当对象年龄达到jvm设定的阈值时才能进入。

为了适应jvm中内存的分配情况,可以动态设定对象进入老年代的时机,不用非要等到指定年龄时才能进入老年代。比如说,如果在survivor区中相同年龄所有对象大小的总和大于survivor空间的一半时,年龄大于或等于该年龄的对象就直接进入老年代。此种情况是为了在minor gc中避免过多的内存复制操作。

5.空间分配担保

在发生minor gc之前,jvm会检查老年代中最大可用连续空间是否大于新生代所有对象的总空间,如果大于,minor gc是安全的。
如果小于,查看是否允许担保失败,如果允许,检查老年代中最大连续可用空间是否大于历次从新生代晋升到老年代的平均大小,如果大于,minor gc安全,否则,触发老年代一次full gc。

6.GC方式

minor gc:发生在新生代的垃圾收集动作,新生代对象大多朝生夕死,minor gc比较频繁

major/full gc:发生在老年代的垃圾收集动作,在老年代中无法承载从新生代中存活下来的对象时,会触发full gc,速度慢,不频繁

你可能感兴趣的:(jvm)