堆空间用来干嘛的?
我们知道基础类型的变量、对象的引用既可以在栈也可以在堆上,但是对象一定是在堆空间的。
堆上存储的是从GC Root可达的活跃对象。
什么是GC Root?
垃圾回收器在判断哪些对象该回收的时候,需要一个标准,那就是从GC Root开始,看看哪些对象能访问到,访问到的就认为还有用,保留下来,其他的回收掉。而这些GC Root可以认为是一些特殊的对象,本质上也还是对象。
哪些是GC Root?
栈上的局部变量
活跃的线程对象
JNI接口使用的对象
类的静态变量
堆的划分?
新生代:存储的是年轻一些的对象。
-Eden:新创建的对象会放在Eden,当空间不足时,会触发Minor GC
-Survivor:有两个一样大小的区域,称为S0和S1,用于存放相对年轻的对象,在Survivor区经过多次垃圾回收仍未释放的对象,会移动到老年代
老年代:存储的是长期存活的对象,来自Survivor区或者超过一定阈值的新创建的对象。当空间不足,会触发Major GC
Minor GC算法
Minor GC流程:
Eden区所有活跃对象age++,移动到S0/S1
S1/S0中所有活跃对象age++并判断是否大于阈值(这个age就是经历过Minor GC的次数),大于阈值的对象会移动到老年代,否则移动到S0/S1
回收Eden区和S1/S0的对象。
在Eden区分配空间给新对象。
当然,S0和S1是交替使用的,上一次S0是空的,这次S1就是空的。
这里的阈值可以通过-XX:MaxTenuringThreshold来设置,默认值15,当设置大于15时,会有问题,用于不会移动到老年代。
模拟Minor GC流程
初始对象都分配在Eden,红色代表待回收,绿色代表活跃对象。S0和S1是空的,尚未进行过垃圾回收,我们默认S0是initial Target(往这个区域移动)
进行一次垃圾回收,B、C、E、F的age++,直接移动到S0
S1没有对象,不需要移动
Eden区域待回收对象A、D、G被移除
新H对象在Eden区域分配空间
某次分配对象时,又需要Minor GC。
此时S0有使用,说明S1是Target,我们看下流程。
Eden区域的活跃对象I、J、K的age++,移动到S1
S0区域的活跃对象C、E、F先age++,判断还未达到阈值,则移动到S1
清除Eden的H、L、M,清除S0的B
分配N的空间
当某次回收时,发现存在age等于14的对象
此时在S1区域内有age等于14的活跃对象,这个时候会直接移动到老年代。
几个常用的配置
-Xms堆空间的最小值
-Xmx堆空间的最大值
-XX:NewSize 新生代最小值
-XX:MaxNewSize 新生代最大值
-XX:SurvivorRatio S0或S1与Eden的相对大小,
假如-XX:SurvivorRatio = 6,那么表示 ,即
-XX:NewRatio 老年代和新生代的相对大小,
假如-XX:NewRatio = 3,那么表示, 即 ,
-XX:PretenureSizeThreshold 表示超过这个大小的对象,直接放到老年代,而不是Eden
推荐分配:新生代占25%~33%的堆内存大小。