为什么我的 Java 程序在 Thread 对象上调用 run() 时会泄漏内存?
(Jeopardy风格的问题,我希望当我遇到这个问题时,答案已经在线)
使用Java 1.4,我有一个方法,我想在某些时候作为线程运行,但在其他时候则不行。所以我把它声明为Thread的子类,然后根据我需要什么调用start()或run()。
但是我发现我的程序会随着时间的推移而泄漏内存。我做错了什么?
(Jeopardy风格的问题,我希望当我遇到这个问题时,答案已经在线)
使用Java 1.4,我有一个方法,我想在某些时候作为线程运行,但在其他时候则不行。所以我把它声明为Thread的子类,然后根据我需要什么调用start()或run()。
但是我发现我的程序会随着时间的推移而泄漏内存。我做错了什么?
这是Java 1.4中的一个已知错误:http://bugs.sun.com/bugdatabase/view_bug.do;jsessionid=5869e03fee226ffffffffc40d4fa881a86e3:WuuT?bug_id=4533087
它在Java 1.5中是固定的,但Sun不打算在1.4中修复它。
问题是,在构造时,会将 a 添加到内部线程表中的引用列表中。在其 start() 方法完成之前,它不会从该列表中删除。只要该引用存在,它就不会被垃圾收集。Thread
因此,除非您肯定要调用其方法,否则切勿创建线程。不应直接调用对象的方法。start()
Thread
run()
编写代码的更好方法是实现接口而不是子类。当您不需要线程时,调用Runnable
Thread
myRunnable.run();
当您确实需要线程时:
Thread myThread = new Thread(myRunnable);
myThread.start();
我怀疑构造线程的实例或其子类是否会泄漏内存。首先,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(".");
}
}
}
编辑:只是为了总结上面测试的想法。线程的 MyThread 子类的每个实例都引用其自己的 10 MB 数组。如果MyThread的实例没有被垃圾回收,JVM将很快耗尽内存。但是,运行测试代码表明,无论到目前为止构造了多少个 MyThread,JVM 都在使用少量恒定的内存。我声称这是因为MyThread的实例是垃圾回收的。