2008-09-20 53 views
26

(Jeopardy風格的問題,我希望答案已經在線,當我有這個問題)當我調用Thread對象的run()時,爲什麼我的Java程序會泄漏內存?

使用Java 1.4,我有一個方法,我想運行一些線程的時間,但不是在其他人。所以我將它聲明爲Thread的子類,然後根據我需要的調用start()或run()。

但我發現我的程序會隨着時間流逝而泄漏內存。我究竟做錯了什麼?

回答

45

這是一個已知的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(); 
+0

這是一個與實現相關的問題(比如說Sun的JVM),還是它在Java語言規範中的某個地方? – Alexander 2008-09-20 10:35:33

+0

編輯 - 我做了一些更多的調查,這是一個JVM錯誤 – slim 2008-09-21 10:29:31

2

讓我們看看如果我們能找到更接近問題的核心:

如果你開始你的程序(可以說)1000 x使用開始(),然後1000 x使用run()在一個線程中,做兩個鬆散的內存?如果是這樣,那麼應該檢查你的算法(即對於外部對象,比如你的Runnable中使用的向量)。

如果沒有像上面描述的那樣的內存泄漏,那麼您應該調查有關JVM的線程的啓動參數和內存使用情況。

3

我懷疑構造一個線程或其子類的實例泄漏內存。首先,在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的實例被垃圾收集。

相關問題