当我在Thread对象上调用run()时,为什么我的Java程序会泄漏内存?
-
01-07-2019 - |
题
(危险的问题,我希望当我遇到这个问题时答案已经在线)
使用Java 1.4,我有一个方法,我想在某些时候作为一个线程运行,但不是在其他人。所以我将它声明为Thread的子类,然后根据我的需要调用start()或run()。
但我发现我的程序会随着时间的推移泄漏内存。我做错了什么?
解决方案
这是Java 1.4中的已知错误: http://bugs.sun.com/bugdatabase/view_bug 。做; JSESSIONID = 5869e03fee226ffffffffc40d4fa881a86e3:WuuT bug_id = 4533087
它已在Java 1.5中修复,但Sun并不打算在1.4中修复它。
问题在于,在构建时, Thread
被添加到内部线程表中的引用列表中。在start()方法完成之前,它不会从该列表中删除。只要该引用存在,就不会收集垃圾。
所以,除非你肯定会调用它的 start()
方法,否则永远不要创建一个线程。不应直接调用 Thread
对象的 run()
方法。
更好的编码方法是实现 Runnable
接口而不是子类 Thread
。如果您不需要线程,请致电
myRunnable.run();
当你需要一个帖子时:
Thread myThread = new Thread(myRunnable);
myThread.start();
其他提示
我怀疑构造一个Thread或其子类的实例会泄漏内存。首先,Javadocs或Java语言规范中没有提到任何类型。其次,我运行了一个简单的测试,它还显示没有内存泄漏(至少在32位x86 Linux 2.6上没有Sun的JDK 1.5.0_05):
public final class Test {
public static final void main(String[] params) throws Exception {
final Runtime rt = Runtime.getRuntime();
long i = 0;
while(true) {
new MyThread().run();
i++;
if ((i % 100) == 0) {
System.out.println((i / 100) + ": " + (rt.freeMemory() / 1024 / 1024) + " " + (rt.totalMemory() / 1024 / 1024));
}
}
}
static class MyThread extends Thread {
private final byte[] tmp = new byte[10 * 1024 * 1024];
public void run() {
System.out.print(".");
}
}
}
编辑:只是总结一下上面测试的想法。 Thread的MyThread子类的每个实例都引用它自己的10 MB数组。如果MyThread的实例没有被垃圾收集,那么JVM会很快耗尽内存。但是,运行测试代码表明,无论目前构建的MyThread数量是多少,JVM都使用少量的内存。我声称这是因为MyThread的实例被垃圾收集。
让我们看看我们是否能够更接近问题的核心:
如果你使用start()开始你的程序(比方说)1000 x,然后在一个线程中使用run()1000 x,那么两个内存都松散吗?如果是这样,那么应该检查你的算法(即对于外部对象,例如你的Runnable中使用的Vector)。
如果没有如上所述的内存泄漏,那么您应该调查有关JVM的线程的启动参数和内存使用情况。