当我在Thread对象上调用run()时,为什么我的Java程序会泄漏内存?

(危险的问题,我希望当我遇到这个问题时答案已经在线)

使用Java 1.4,我有一个方法,我想在某些时候作为一个线程运行,但不是在其他人。 所以我将它声明为Thread的子类,然后根据我的需要调用start()或run()。

但我发现我的程序会随着时间的推移泄漏内存。 我究竟做错了什么?

这是Java 1.4中的一个已知错误: http : //bugs.sun.com/bugdatabase/view_bug.do; jsessionid = 5886e03fee226ffffffffc40d4fa881a86e3 : 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的线程的启动参数和内存使用情况。