(Jeopardy風格的問題,我希望答案已經在線,當我有這個問題)當我調用Thread對象的run()時,爲什麼我的Java程序會泄漏內存?
使用Java 1.4,我有一個方法,我想運行一些線程的時間,但不是在其他人。所以我將它聲明爲Thread的子類,然後根據我需要的調用start()或run()。
但我發現我的程序會隨着時間流逝而泄漏內存。我究竟做錯了什麼?
(Jeopardy風格的問題,我希望答案已經在線,當我有這個問題)當我調用Thread對象的run()時,爲什麼我的Java程序會泄漏內存?
使用Java 1.4,我有一個方法,我想運行一些線程的時間,但不是在其他人。所以我將它聲明爲Thread的子類,然後根據我需要的調用start()或run()。
但我發現我的程序會隨着時間流逝而泄漏內存。我究竟做錯了什麼?
這是一個已知的bug在Java 1.4中: http://bugs.sun.com/bugdatabase/view_bug.do;jsessionid=5869e03fee226ffffffffc40d4fa881a86e3:WuuT?bug_id=4533087
它固定在Java 1.5中,但Sun並不打算將其固定1.4。
問題是,在構建時,Thread
被添加到內部線程表中的引用列表中。在start()方法完成之前,它不會從該列表中刪除。只要這個參考在那裏,它就不會被垃圾收集。
所以,除非你一定要打電話給start()
方法,否則不要創建線程。 A Thread
對象的run()
方法不應該直接調用。
更好的編碼方式是實現Runnable
接口而不是子類Thread
。當你不需要一個線程調用
myRunnable.run();
當你需要一個線程:
Thread myThread = new Thread(myRunnable);
myThread.start();
讓我們看看如果我們能找到更接近問題的核心:
如果你開始你的程序(可以說)1000 x使用開始(),然後1000 x使用run()在一個線程中,做兩個鬆散的內存?如果是這樣,那麼應該檢查你的算法(即對於外部對象,比如你的Runnable中使用的向量)。
如果沒有像上面描述的那樣的內存泄漏,那麼您應該調查有關JVM的線程的啓動參數和內存使用情況。
我懷疑構造一個線程或其子類的實例泄漏內存。首先,在Javadocs或Java語言規範中沒有提及的種類。其次,我進行了簡單的測試,它也表明,沒有內存泄漏(至少不是Sun的JDK 1.5.0_05 32位x86的Linux 2.6):
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會很快耗盡內存。但是,運行測試代碼表明,不管迄今爲止構建的MyThreads的數量是多少,JVM都使用少量的內存。我聲稱這是因爲MyThread的實例被垃圾收集。
這是一個與實現相關的問題(比如說Sun的JVM),還是它在Java語言規範中的某個地方? – Alexander 2008-09-20 10:35:33
編輯 - 我做了一些更多的調查,這是一個JVM錯誤 – slim 2008-09-21 10:29:31