我正在尝试使用visualvm进行一些内存分析。 我编写了一个基本代码,它运行一个无限循环来向List添加对象。
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);
}
}
}
正如预期的那样,内存会在连接的visualvm 1st快照中显示,即 Memory_Shoots.JPG 。
但是,如果我从代码中删除以下注释并允许程序休眠1秒;结果不同:
Thread.sleep(1000L);
内存增加但随后稳定并继续。请参阅附加的第二张快照,即 Memory_Stabilizes.JPG
我无法理解这种行为? 能否请您提供意见。
答案 0 :(得分:4)
查看稍微修改过的代码版本(固定迭代次数,在启动后添加5s暂停以允许我的IDE连接到visualvm,删除system.out.print以获得速度等)似乎你的罪魁祸首是垃圾收集:
100L睡眠:(跑5:18)
10L睡眠:(跑5:01)
2L睡眠:(跑4:57)
1L睡眠:(跑6:36)
0L睡眠:(跑0:23)
所以基本上我们发现使用的堆将缓慢上升,直到Eden空间被填满(导致分配失败),将伊甸园的旧成员(几乎全部,看着空间使用)移动到幸存者0 / 1,其中一些是旧的。睡眠和不睡眠之间的区别很可能是次要收藏品和主要收藏品的相对频率之间的差异。
答案 1 :(得分:2)
有几件事值得考虑:
这第二个值可以是很多东西。数组列表会经常产生一些垃圾。创建字符串“nameConst + i”的过程将导致一些垃圾对象。
假设答案是PersonDetail很小但是需要一个中等量的内存来制作一个。然后,JVM将为你制作的每个PersonDetail扔掉一堆垃圾(垃圾收集)。当您创建PersonDetails时,垃圾堆积起来,最终JVM将收集垃圾。垃圾收集步骤将找到大量可用内存,因为大多数分配都是短期对象。这可能会产生一个像你的第二张照片中的图形,锯齿,使用内存然后收集大量垃圾。
现在想象一下你快速创建一堆对象(没有sleep语句)。现在,使用的总内存将通过垃圾和您在列表中保存的对象快速上升。当你到达最大内存时,垃圾收集必须更频繁地发生。有点像顶部图。
我不确定发生了什么,但你可以做的一件事就是查看VisualVM中的采样,看看有多少对象是由类创建的,更重要的是它们占用了多少内存。将PersonDetails使用的数量与其他需要的垃圾进行比较。