JVM堆和垃圾回收

521 阅读1分钟

前言

只讲大概,不扣细节。

堆结构

image.png

关于垃圾回收

  • Minor GC 针对年轻代。
  • 垃圾回收一般使用可达性分析算法。
  • 可达性分析算法会清除没有被其它对象持有引用的对象,第一次被算法分析过的对象如果没有被清除,就会被移到Servivor区的s0,第二次被算法分析过的且没被清除的对象,会被移到s1,第二次往后每被分析一次,如果没被清除,就会从s0移到s1或者从s1移到s0。每一次移动对象头的分代年龄+1,当对象头的分代年龄等于15时会被移到老年代,或者Servivor区放不下的对象会被直接移到老年代。
  • 对象不只是有对象的数据信息,还有对象头信息。

对象头

image.png

垃圾回收测试

  • 循环引用
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演示一波垃圾回收

动画3.gif

  • 可以观察到:s0和s1是交替填充的,gc是在Eden区填充之后触发的。
  • 当老年代占用了堆内存的45%时,就会触发混合回收,也就是对新生代和老年代同时进行垃圾回收。上图中老年代已经很多了,所以没等到Eden区满就触发gc了。
  • 最终内存溢出了(OOM)

image.png