Почему в моей Java-программе происходит утечка памяти, когда я вызываю run() для объекта Thread?

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

Вопрос

(Вопрос в стиле Jeopardy, хотелось бы, чтобы ответ был в Сети, когда у меня возникла эта проблема)

Используя Java 1.4, у меня есть метод, который я хочу запускать как поток некоторое время, но не в других случаях.Поэтому я объявил его как подкласс Thread, затем либо вызвал start(), либо run() в зависимости от того, что мне было нужно.

Но я обнаружил, что со временем в моей программе будет происходить утечка памяти.Что я делаю не так?

Это было полезно?

Решение

Это известная ошибка в 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();

Другие советы

Я сомневаюсь, что при создании экземпляра потока или его подкласса происходит утечка памяти.Во-первых, нет ничего подобного, упомянутого в Javadocs или спецификации языка Java.Во-вторых, я провел простой тест, и он также показывает, что утечки памяти нет (по крайней мере, не в Sun's 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(".");
    }
  }
}

Редактировать:Просто резюмирую идею приведенного выше теста.Каждый экземпляр подкласса MyThread потока ссылается на свой собственный массив размером 10 МБ.Если бы экземпляры MyThread не собирали мусор, у JVM довольно быстро закончилась бы память.Однако запуск тестового кода показывает, что JVM использует небольшой постоянный объем памяти независимо от количества созданных на данный момент MyThreads.Я утверждаю, что это происходит потому, что экземпляры MyThread собирают мусор.

Давайте посмотрим, сможем ли мы подобраться ближе к сути проблемы:

Если вы запускаете свою программу (допустим) 1000 раз с помощью start(), затем 1000 раз с помощью run() в потоке, теряют ли оба память?Если это так, то ваш алгоритм должен быть проверен (т.е.для внешних объектов, таких как векторы, используемые в вашем Runnable).

Если такой утечки памяти, как описано выше, нет, то вам следует узнать о начальных параметрах и использовании памяти потоками, относящимися к JVM.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top