最近学习了JVM内存模型有关知识,一开始看书的时候对GC(垃圾回收机制)始终不太清楚,只知道GC的方法,但是没有具体的理解,直到在看视频的时候了解到了一款java的jdk自带的监控程序。首先打开cmd窗口,输入jvisualvm就可以进入到Java VisualVM窗口

java jvm heap 快照 jvm heap space_JVM


随后我们如果想要查看GC过程中java堆中各区域的情况需要下载一个插件

下载完插件之后。我们需要打开idea运行如下代码。

public class HeapTest {
    byte[] a = new  byte[1024*100];
    public static void main(String[] args) throws InterruptedException  {
        ArrayList<HeapTest> heapTests = new ArrayList<>();
        while(true){
            heapTests.add(new HeapTest());
            Thread.sleep(10);
        }
    }
}

由于每new一个HeapTest,都会将其加入到ArrayList中,所以这个对象因为被ArrayList引用而导致无法被回收,运行一段时间后就会报出Java heap space的错误。我们可以利用刚才下载的插件对GC过程中的堆区变化进行一个图像化的监测

java jvm heap 快照 jvm heap space_Java_02


我们可以发现,随着程序的运行,首先Eden区因为存储new出来的HeapTest而被占用,经过一段时间之后这些对象被移动到Survivor 0区,这时第一次GC结束,下一次GC会将Survivor 0区的对象和Eden中的对象移动到Survivor 1区,在GC过程中,每次都会将Survivor中的一个区域的对象移动到另一个Survivor区域,同时清空Eden和移动后Survivor区中的对象,当新生代中的对象引用的次数超过15次后,则将这个对象放到Old区,但是,由于代码的原因,实际上在代码运行期间,GC并没有删除某个对象,而是将这些对象都放到了Old区,这是因为JVM使用可达性分析进行GC,但是由于代码中每个new出的对象都被引用了,所以导致每个对象都是可达的,也就是每个对象都不算是垃圾,也就不能回收。所以这就会导致Old区的对象越来越多,直到没有空间最终报出Java heap space的错误。