前言
只讲大概,不扣细节。
堆结构
关于垃圾回收
- Minor GC 针对年轻代。
- 垃圾回收一般使用可达性分析算法。
- 可达性分析算法会清除没有被其它对象持有引用的对象,第一次被算法分析过的对象如果没有被清除,就会被移到Servivor区的s0,第二次被算法分析过的且没被清除的对象,会被移到s1,第二次往后每被分析一次,如果没被清除,就会从s0移到s1或者从s1移到s0。每一次移动对象头的分代年龄+1,当对象头的分代年龄等于15时会被移到老年代,或者Servivor区放不下的对象会被直接移到老年代。
- 对象不只是有对象的数据信息,还有对象头信息。
对象头
垃圾回收测试
- 循环引用
public class HeapTest {
byte[] bytes= new byte[1024*100];//100k
public static void main(String[] args) throws InterruptedException {//循环引用
List<HeapTest> heapTestList = new ArrayList<>();
while (true){
heapTestList.add(new HeapTest());
Thread.sleep(100);
}
}
}
heapTestList对象引用被HeapTest持有,HeapTest对象引用被heapTestList持有,导致可达性分析算法无法清除对象,最终可能会内存溢出。
- 用jvisualvm演示一波垃圾回收
- 可以观察到:s0和s1是交替填充的,gc是在Eden区填充之后触发的。
- 当老年代占用了堆内存的45%时,就会触发混合回收,也就是对新生代和老年代同时进行垃圾回收。上图中老年代已经很多了,所以没等到Eden区满就触发gc了。
- 最终内存溢出了(OOM)