在jvm堆内存中分为年轻代与老年代,年轻代又分为Eden区与Survivor区.新对象的创建会分配在年轻代,那么对象何时进入老年代呢?又有什么样的对象适合放在老年代呢?
YoungGC与FullGC简单区别
YoungGC波及范围小(年轻代),且不会停止应用进程工作,YoungGC发生频率高,但是回收速度较快,对于程序运行没有太大影响.
FullGC波及范围广(堆内存与方法区)会停止应用进程工作(视垃圾收集器而定),FullGC发生频率低,但是回收速度一般是YoungGC的十倍以上,对于程序运行影响较大
触发YoungGC的策略一般是年轻代的Eden区或者Survivor区放满之后,FullGC触发条件则更多一些,一个基本策略是老年代放满之后(CMS垃圾收集器有容量上限),触发GC策略不在本文做过多解释
因此,了解对象何时进入老年代有利于我们合理分配堆内存,减少FullGC的发生.
对象进入老年代策略
迭代年龄判断
在对象的对象头信息中存储着对象的迭代年龄,迭代年龄会在每次YoungGC之后对象的移区操作中增加,每一次移区年龄加一.当这个年龄达到15(默认)之后,这个对象将会被移入老年代.
- XX:MaxTenuringThreshold
复制代码
我们可以通过这个参数设置这个年龄值
大对象直接进入老年代
有一些占用大量连续内存空间的对象在被加载伊始就会直接进入老年代.这样的大对象一般是一些数组,长字符串之类的对象.
- XX:PretenureSizeThreshold
复制代码
我们可以通过这个参数设置大对象,这个限额的大小.
YoungGC之后需要移区的对象放不下
在进行移区的时候,可能需要移区的对象大于所移区的空间大小,那么这些对象会被直接放入老年代,毕竟总不能在对象还被引用的时候就对其进行回收.那么在这里我们需要讲述一下对象的几种引用类型.下面引用类型等级依次向下
- 强引用:平常的代码创建对象都属于强引用,之后当对象变为垃圾对象才会被回收
- 软引用:被SoftReference这个类包裹起来的对象,在进行垃圾收集发现剩余空间不够的时候,全部已创建软引用对象会被一次性回收,这种引用类型常用于对内存比较敏感的缓存中
- 弱引用:被WeekReference这个类包裹起来的对象,每次进行垃圾收集操作的时候都会将弱引用对象一次性回收,基本不使用
- 虚引用:又称幽灵引用,随时都会被回收
对象动态年龄判断
此策略发生在Survivor区,当Survivor区中的一批对象的总大小大于Survivor区空间大小的一半,在这个区域中,对象年龄大于这批对象的最大年龄的所有对象会被移入老年代.看下面的例子
假设我这里按照年龄划分了10批对象,对象年龄依次为1-10,现在年龄1到3这批对象的总大小大于Survivor空间一半,则对象为4-10的所有对象会被放入老年代
什么对象适合存放在老年代
我们依次分析上述策略.
- 策略一:将可能长期存活的对象直接放入老年代
- 策略二:避免移区时的复制操作浪费资源
- 策略三:不能将还有引用的对象当做垃圾回收掉
- 策略四:将可能长期存活的对象直接放入老年代
观察这几条策略并结合GC区别我们可以发现一些端倪.年轻代的空间很宝贵,不应放入长期对象与较大对象占用空间,存活时间短的对象应让其在年轻代存活直至死亡,因为这些对象放入老年代后很快死亡,又不能及时回收,造成内存浪费,更快的触发FullGC.
因此在程序运行过程中,合理设置参数,使一些可能长期存活的框架对象与缓存对象,一些大对象应放入老年代.
参考链接:IT虾米网