Pourquoi mon programme Java perd-il de la mémoire lorsque j'appelle run () sur un objet Thread?

StackOverflow https://stackoverflow.com/questions/107823

Question

(Question de style Jeopardy, j'aimerais que la réponse soit en ligne lorsque j'ai eu ce problème)

Avec Java 1.4, j’ai une méthode que je veux exécuter en tant que thread de temps en temps, mais pas pour d’autres. Je l'ai donc déclaré en tant que sous-classe de Thread, puis j'ai appelé start () ou run () en fonction de mes besoins.

Mais j’ai constaté que mon programme perdrait de la mémoire avec le temps. Qu'est-ce que je fais mal?

Était-ce utile?

La solution

C’est un bogue connu de Java 1.4: .do; jsessionid = 5869e03fee226ffffffffc40d4fa881a86e3: WuuT? bug_id = 4533087

Il est corrigé dans Java 1.5 mais Sun n'a pas l'intention de le corriger dans 1.4.

Le problème est qu’au moment de la construction, un Thread est ajouté à une liste de références dans une table de threads interne. Il ne sera pas supprimé de cette liste jusqu'à ce que sa méthode start () soit terminée. Tant que cette référence est là, elle ne sera pas récupérée.

Donc, ne créez jamais de fil sauf si vous allez vraiment appeler sa 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 est d'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 thread:

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

Autres conseils

Je doute que la construction d'une instance d'un thread ou de l'une de ses sous-classes entraîne une perte de mémoire. Tout d’abord, il n’ya rien de tel que mentionné dans les Javadocs ou les spécifications de langage Java. Deuxièmement, j’ai effectué un test simple et il a également montré qu’aucune mémoire ne fuyait (du moins pas sur le JDK 1.5.0_05 de Sun sur Linux 2.6 x86 32 bits):

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: Juste pour résumer l’idée du 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 machine virtuelle Java s'épuiserait rapidement. Cependant, l’exécution du code de test montre que la machine virtuelle utilise une quantité de mémoire constante, quel que soit le nombre de MyThreads construites jusqu’à présent. Je prétends que cela est dû au fait que les instances de MyThread sont collectées avec les ordures.

Voyons si nous pourrions nous approcher du cœur du problème:

Si vous démarrez votre programme (disons) 1000 x en utilisant start (), puis 1000 x en utilisant run () dans un thread, les deux perdent-ils de la mémoire? Si tel est le cas, vérifiez votre algorithme (c'est-à-dire 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 vous renseigner sur les paramètres de démarrage et l'utilisation de la mémoire des threads relatifs à la machine virtuelle Java.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top