【发布时间】:2013-03-12 19:36:38
【问题描述】:
我正在对 Java 及其允许内存泄漏的能力做一个小实验。我写了这个简单的代码:
import java.util.ArrayList;
import java.util.List;
public class Test {
public static void main(String[] args) {
class Obj {
int i;
Obj(int i) {
this.i = i;
}
}
List<Obj> list;
while(true) {
list = new ArrayList<Obj>();
for(int i = 0; i < 1000; i++) {
Obj o = new Obj(i);
list.add(o);
}
try {
Thread.sleep(1); //<-- added to give the gc time to trash the previous iteration
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
执行此操作时(尤其是每次迭代都会将更多对象添加到列表中),您可以看到使用的内存量迅速增加。在每次迭代中添加 10000 个对象时,我能够非常快速地达到 2 GB。看起来好像列表(以及其他类型的使用“链表”列表功能的对象)不喜欢被删除。
当我没有将对象添加到列表中时,内存堆根本没有增加(意味着垃圾处理正在完成它的工作)。我尝试将列表重置为 null 每次迭代然后重新声明它以及调用 clear() 方法。似乎没有任何效果。每当我在循环中使用 List 时,我的 RAM 都会呼救。
那么,为什么会发生这种情况?为什么垃圾处理不会在每次迭代时都摆脱列表而不是让它们堆积起来? List 接口不允许这种用法吗?我只是没有给垃圾处理足够的时间来摆脱最后一个实例吗?
【问题讨论】:
-
注意:
Thread.sleep(1)休眠 1 毫秒,而不是 1 秒。 -
是的,我知道。我也尝试过更长的持续时间。
-
使用
System.gc()运行垃圾回收。睡眠没有任何作用。而且list仍然是从当前函数框架中引用的,所以可能没有被收集到。 -
用
VisualVM检查你的代码,内存使用率按预期上升和下降。 -
您在任务管理器中看到的是 JVM 分配了多少内存,而不是有多少空闲/占用。通常,JVM 不愿意将内存还给操作系统,尽管这通常是可配置的。你肯定在这里猎鬼。
标签: java list loops memory-leaks