试图理解java中的垃圾收集

试图理解java中的垃圾收集,java,collections,garbage-collection,garbage,Java,Collections,Garbage Collection,Garbage,试图用下面的代码理解GC public class Test1 { public static void main(String[] args) { //HashMap<String,String> newmap = new HashMap<String,String>(); //CleanUpThread t = new CleanUpThread(newmap); ArrayList<Double>

试图用下面的代码理解GC

public class Test1 {
    public static void main(String[] args) {

        //HashMap<String,String> newmap = new HashMap<String,String>();
        //CleanUpThread t = new CleanUpThread(newmap);
        ArrayList<Double> al = new ArrayList<Double>();
        //t.start();
        while(true){

            al.add(Math.random());


            try {
                Thread.currentThread().sleep(200);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }

        }


    }
}
公共类Test1{
公共静态void main(字符串[]args){
//HashMap newmap=新HashMap();
//CleanUpThread t=newcleanupthread(newmap);
ArrayList al=新的ArrayList();
//t、 start();
while(true){
al.add(Math.random());
试一试{
Thread.currentThread().sleep(200);
}捕捉(中断异常e){
//TODO自动生成的捕捉块
e、 printStackTrace();
}
}
}
}
由于我在列表中创建随机的双对象,所以我希望出现内存不足错误,堆被填满

但我看到我的GC正在清理,幸存者空间中只保留了约1Mb的数据

运行jvm时,将32MB堆大小和GC占用率设置为30%


任何人都可以对这种行为给出更多的解释。

首先,您没有出现OutOfMemoryError,因为代码中的对象创建速度非常慢(每200毫秒一次)。尝试删除
sleep
代码片段

其次,如果GC清理了幸存者空间中的数据,并不意味着GC会从内存中删除这些对象。这意味着,GC将这些对象移到了旧一代,因为它们经历了多次垃圾收集。您可以看到,老一代的规模只会增长,没有发生垃圾收集

当堆大小被填满时,GC将尝试清理对象(您将在GC时间图表上看到经常出现的波动),但是这种尝试将不成功,因为它将不会删除任何对象。随着时间的推移,您将收到OME

我认为如果你删除
sleep
代码片段并等待足够的时间,你就会收到OME


为了获得更快的结果,您可以减小堆的大小。

只要您的Eden空间被填满,就会运行次要GC,并将活动对象传输给幸存者。经过一些迭代后,长寿命的幸存者对象被转移到旧的生成空间

在您的例子中,只要Eden空间耗尽到一定百分比,并且旧代的大小随着时间的推移而增加,就会运行minor GC。你可以在图表中看出这一点

取消睡眠时间间隔,它会给你一个更清晰的视野。此外,还可以配置堆大小以更好地进行分析

欲了解更多信息,请参考

你做了一个实验多长时间?让它继续运行就行了。那会发生什么?谢谢你提供的信息。真的很有帮助。我还尝试删除al.add(Math.random());一段代码本身,并在循环运行时保持。即使在这种情况下,我也看到伊甸园的空间像以前一样在增加。我现在还没有创建对象的代码,但是为什么伊甸园的空间会越来越大呢?我对此感到困惑,这是个好问题。我试图复制您的示例,并确保堆大小增加。我建议它自己创建JVM对象。除此之外,当您使用JVisualVM连接到java进程时,有必要为java进程和JVisualVM探查器之间的通信分配一些对象。这两个示例之间的区别在于当您在列表中添加双精度时GC无法清理对象,但是在空while循环中,垃圾收集发生得很好,没有理由出现OutOfMemoryError。是的,非常感谢您的回复。我还试着从代码中去掉睡眠因素。观察到,当尝试连接到此进程时,jvisualVM根本没有响应,最终java程序被终止,超出了OOM GC开销限制。@kaushikHS当您删除
睡眠时,JVM将以如此高的速率分配,以至于连接到JVM可能会失败,因为它无法响应。在开始处(即循环之前)插入一个
睡眠
,以便能够在JVM进入重分配循环之前连接到JVM。请注意,当您使用VisualVM之类的工具连接到JVM时,通信本身也会产生垃圾,因此即使删除了所有应用程序分配,在监视时仍会有一些稳定的分配。