2008-09-20 17 views
26

(Pytanie w stylu zagrożenia, chciałbym, aby odpowiedź była w trybie online, gdy miałem ten problem)Dlaczego mój program w języku Java wycieka z pamięci po wywołaniu metody run() na obiekcie Thread?

Używając Java 1.4, mam metodę, którą chcę uruchomić jako wątek przez pewien czas, ale nie w innych . Tak więc zadeklarowałem to jako podklasę wątku, a następnie albo nazwano start() lub run() w zależności od tego, czego potrzebowałem.

Ale odkryłem, że mój program z czasem wycieknie z pamięci. Co ja robię źle?

Odpowiedz

45

To znany błąd w Java 1.4: http://bugs.sun.com/bugdatabase/view_bug.do;jsessionid=5869e03fee226ffffffffc40d4fa881a86e3:WuuT?bug_id=4533087

Jest ustalona w Sun Java 1.5, ale nie zamierza go naprawić w 1.4.

Problem polega na tym, że w czasie budowy do tabeli referencyjnej dodawana jest tabela Thread. Nie zostanie usunięty z tej listy, dopóki nie zostanie zakończona jego metoda start(). Tak długo, jak to odniesienie istnieje, nie będzie zbierać śmieci.

Nigdy nie twórz wątku, chyba że definitywnie nazwiesz metodę start(). Metoda Thread obiektu obiektu nie powinna być wywoływana bezpośrednio.

Lepszym sposobem kodowania jest implementacja interfejsu Runnable zamiast podklasy Thread. Kiedy nie trzeba nić, zadzwoń

myRunnable.run(); 

gdy potrzebujemy wątek:

Thread myThread = new Thread(myRunnable); 
myThread.start(); 
+0

Czy jest to kwestia zależna od implementacji (powiedzmy, JVM firmy Sun), czy jest ona opisana gdzieś w specyfikacji języka Java? – Alexander

+0

Edytowany - Zrobiłem więcej badań i jest to błąd JVM – slim

2

Zobaczmy, czy możemy dostać się bliżej do sedna problemu:

Jeśli uruchamiasz swój program (powiedzmy) 1000 x używając start(), następnie 1000 x używając run() w wątku, czy masz luźną pamięć? Jeśli tak, to należy sprawdzić algorytm (np. W przypadku obiektów zewnętrznych, takich jak wektory używane w Runnie).

Jeśli nie ma wycieku pamięci, jak opisano powyżej, należy zbadać parametry początkowe i użycie pamięci wątków dotyczących JVM.

3

Wątpię, aby konstrukcja instancji wątku lub jego podklasy spowodowała wyciek pamięci. Po pierwsze, nic nie jest wymienione w Javadocs lub specyfikacji języka Java. Po drugie, wpadłem prosty test i to również pokazuje, że nie wyciekły pamięci (przynajmniej nie na Sun JDK 1.5.0_05 na 32-bitowym systemie Linux x86 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("."); 
    } 
    } 
} 

EDIT: Żeby podsumować ideę powyższy test. Każde wystąpienie podklasy MyThread wątku odwołuje się do własnej tablicy 10 MB. Jeśli instancje MyThread nie zostały zebrane, JVM bardzo szybko zabraknie pamięci. Jednak uruchomienie kodu testowego pokazuje, że JVM używa małej stałej ilości pamięci niezależnie od liczby skonstruowanych do tej pory MyThreads. Twierdzę, że dzieje się tak, ponieważ instancje MyThread są zbierane na śmieci.

+3

Aha - zrobił kilka dalszych badań i odkrył, że to błąd, który został naprawiony w Javie 1.5 – slim