在复习Java内存机制的过程中有一些新问题,自问自答,做个记录。
新生代是java堆内存的一部分。堆内存分新生代和老生代两大块,也有把堆内存分为新生代老生代永久代(持久代)三块的说法。(不过这种说法应该逐渐被淘汰,因为从java7开始永久代就已经被移除了。)
新生代继续细分,可以划分出Eden,SurvivorFrom,SurvivorTo三块,Eden区和Survivor的两个区大小的比例默认为8:1:1,新创建的对象如果不是特别大都分配在Eden区和SurvivorFrom,在新生代GC后,这两块内存中仍然存活的对象会被复制到SurvivorTo中或复制到老年代。

1、什么时候触发新生代GC?
在Eden区空间不足时会触发新生代的GC。

2、为什么Survivor区要空出一块?
典型的空间换时间,用10%的新生代内存的浪费,换取新生代GC时更高的效率。由于新生代的对象大多存活时间短,因此时间上更高效的复制算法是更合适的选择,空出一块用于复制存活对象也就是自然而然的选择。

3、新生代的GC用什么回收算法?
上文提到,复制算法。复制算法将还存活的对象直接复制到另一块内存上,再将被复制的内存清空。优点是不会产生内存碎片,实现简单高效,缺点也显而易见,总是会有一部分的内存处于空闲状态。

4、GC的过程的怎样的?
GC触发时,Eden区中存活的对象会被直接复制到SurvivorTo区,SurvivorFrom区中年龄超过配置的对象会复制到老年代,年龄没有达到配置值的对象也被复制到SurvivorTo中。

5、GC时SurvivorTo内存不够怎么处理?
研究表明98%情况下对象都是很快消亡,Survivor区分为两块,而不是三块四块也是为了避免Survivor区过于碎片化的权衡结果,因此在大多数情况下不会出现复制时Survivor区大小不足的情况。如果真的频繁出现,可能需要更改配置,增大Survivor区的内存占比。

6、GC之前如何判断对象是否存活?
主流的实现都是使用可达性分析算法来判断。可达性分析算法是指,以一系列被定义为GC Roots的对象为起点,开始向下搜索引用链,可以到达的对象判断为存活,不可到达的标记为可回收。GC Roots对象包括本地变量表中引用的对象,类静态属性引用的对象(例如一些public static的String对象),方法区中常量引用的对象等。可达性分析算法相比于引用计数算法最大的优势是很好的解决了循环引用的两个对象不能被回收的问题。

04-21 09:44