Java内存行为:与Thread.sleep不同

4

我正在尝试使用visualvm进行一些内存分析。 我编写了一个基本代码,运行一个无限循环将对象添加到列表中。

package home.always.learning.java;  

import java.util.ArrayList;  
import java.util.List;  

public class Heaper {  

    private static List<PersonDetails> listObj = new ArrayList<PersonDetails>();  

    private static final String nameConst = "Tarun Trehan";  

    public static void main(String[] args)throws Exception{  
        personListCreation();  
    }  

    public static void personListCreation() throws Exception  
    {  
        int i = 0;  
        while(true)  
        {  
            System.out.println("Looping to create person list...");  
            i++;  
            listObj.add(new PersonDetails(nameConst+i));  
            //Thread.sleep(1000L);  
        }  
    }  
}  

作为预期,内存飙升并在附加的第一个快照中可见,即Memory_Shoots.JPG。然而,如果我从代码中删除以下注释并允许程序睡眠1秒钟,结果就会有所不同。
Thread.sleep(1000L);

内存增加后稳定下来并继续保持。请参考附加的第二个快照,即 Memory_Stabilizes.JPG

我无法理解这种行为?您能否提供您的意见。

Memory_Shoots

Memory_Stabilizes


3
比较相同的循环次数所表现出的行为,而不是相同的时间长度。 - Matt Ball
显然,它会慢得多,但可以实现相同的效果。 - Thomas Jungblut
嗨,我能够观察到使用Thread.sleep后内存的增加。正如正确指出的那样,增长速度很慢,但行为和占用的内存最终将是相同的。谢谢!!! - Allzhere
2个回答

4
看着稍微修改过的代码(固定迭代次数,启动后添加5秒暂停以允许我的IDE连接到visualvm,为了速度移除了system.out.print等),似乎你的罪魁祸首是垃圾回收: 100L睡眠:(运行了5:18) garbage collection with sleep garbage collection with sleep 10L睡眠:(运行了5:01) garbage collection with sleep garbage collection with sleep 2L睡眠:(运行了4:57) garbage collection with sleep garbage collection with sleep 1L睡眠:(运行了6:36) garbage collection with sleep garbage collection with sleep 0L睡眠:(运行了0:23) garbage collection with sleep garbage collection with sleep 因此,我们发现使用的堆将缓慢上升,直到伊甸园空间被填满(导致分配失败),将伊甸园中的旧成员(几乎所有成员,从空间使用情况来看)移动到survivor 0/1,其中一些移动到老年代。睡眠和不睡眠之间的差异很可能是次要收集和主要收集相对频率之间的差异。

2

有几件事情值得思考:

  • 这些PersonDetail对象有多大?
  • 创建一个不是对象的PersonDetail对象需要多少内存?

第二个值可能是很多东西。ArrayList会定期产生一些垃圾。创建字符串"nameConst+i"将导致一些垃圾对象。

假设答案是PersonDetail很小,但制作一个需要中等数量的内存。那么JVM将有一堆垃圾要丢弃(垃圾回收)每个PersonDetail你做。当你创建PersonDetails时,垃圾会堆积起来,最终JVM会收集它。垃圾回收步骤将找到大量的空闲内存,因为大多数分配都是短暂的对象。这可能会导致一个像你第二张图片中的图形,一个锯齿形,其中内存被使用然后收集了大量的垃圾。

现在想象一下,你快速地创建了一堆对象(没有睡眠语句)。现在总内存使用量将通过垃圾和列表中保存的对象迅速增加。当达到最大内存时,垃圾回收将更频繁地发生。有点像顶部的图表。

我不确定正在发生什么,但你可以做的一件事是查看VisualVM中的采样,看看每个类创建了多少对象,更重要的是它们占用了多少内存。将PersonDetails使用的数量与其他只是需要在需要时清理的垃圾进行比较。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接