2008-09-20 11 views
26

(Jeopardy-question de style, je souhaite la réponse avait été en ligne quand j'ai eu ce problème)Pourquoi mon programme Java perd-il de la mémoire lorsque j'appelle run() sur un objet Thread?

En utilisant Java 1.4, j'ai une méthode que je veux exécuter comme un fil de temps, mais pas à d'autres . Donc je l'ai déclaré comme une sous-classe de Thread, puis soit appelé start() ou run() en fonction de ce dont j'avais besoin.

Mais j'ai trouvé que mon programme fuirait la mémoire au fil du temps. Qu'est-ce que je fais mal?

Répondre

45

Ceci est un bug connu en Java 1.4: http://bugs.sun.com/bugdatabase/view_bug.do;jsessionid=5869e03fee226ffffffffc40d4fa881a86e3:WuuT?bug_id=4533087

Il est fixé en Java 1.5, mais Sun n'a pas l'intention de le fixer dans 1.4.

Le problème est que, au moment de la construction, un Thread est ajouté à une liste de références dans une table de thread interne. Il ne sera pas supprimé de cette liste tant que sa méthode start() ne sera pas terminée. Tant que cette référence est là, elle ne sera pas récupérée. Donc, ne créez jamais un sujet à moins que vous ne décidiez d'appeler la méthode start(). La méthode run() d'un objet Thread ne doit pas être appelée directement.

Une meilleure façon de le coder consiste à implémenter l'interface Runnable plutôt que la sous-classe Thread. Lorsque vous n'avez pas besoin d'un fil, appelez

myRunnable.run(); 

Lorsque vous avez besoin d'un fil:

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

S'agit-il d'un problème lié à l'implémentation (par exemple, de la JVM de Sun) ou est-il décrit quelque part dans la spécification de langage Java? – Alexander

+0

Modifié - J'ai fait un peu plus d'enquête et c'est un bug de la JVM – slim

2

Voyons voir si nous pouvions se rapprocher au cœur du problème:

Si vous commencez votre programme (disons) 1000 x en utilisant start(), puis 1000 x en utilisant run() dans un thread, faites les deux perdre de la mémoire? Si c'est le cas, votre algorithme doit être vérifié (c'est-à-dire pour les objets externes tels que les vecteurs utilisés dans votre Runnable).

S'il n'y a pas de fuite de mémoire telle que décrite ci-dessus, vous devez étudier les paramètres de démarrage et l'utilisation de la mémoire des threads concernant la machine virtuelle Java.

3

Je doute que la construction d'une instance d'un Thread ou d'une sous-classe de celui-ci fuit la mémoire. Tout d'abord, il n'y a rien des sortes mentionnées dans les Javadocs ou les spécifications de langage Java. En second lieu, j'ai couru un test simple et il montre aussi que pas de mémoire est une fuite (au moins pas de Sun JDK 1.5.0_05 sur 32 bits 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("."); 
    } 
    } 
} 

EDIT: Pour résumer l'idée de le test ci-dessus. Chaque instance de la sous-classe MyThread d'un Thread fait référence à son propre tableau de 10 Mo. Si les instances de MyThread n'étaient pas récupérées, la JVM manquerait de mémoire assez rapidement. Cependant, l'exécution du code de test indique que la machine virtuelle Java utilise une petite quantité constante de mémoire, quel que soit le nombre de MyThreads construits jusqu'à présent. Je prétends que c'est parce que les instances de MyThread sont récupérées par les ordures.

+3

Aha - a fait d'autres recherches et a découvert que c'est un bug qui a été corrigé dans Java 1.5 – slim