Почему моя Java-программа теряет память, когда я вызываю run () для объекта Thread? - PullRequest
27 голосов
/ 20 сентября 2008

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

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

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

Ответы [ 3 ]

47 голосов
/ 20 сентября 2008

Это известная ошибка в 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() метод. Thread Метод run() объекта не должен вызываться напрямую.

Лучший способ кодирования это реализация интерфейса Runnable, а не подкласса Thread. Если вам не нужна нить, звоните

myRunnable.run();

Когда вам нужна нить:

Thread myThread = new Thread(myRunnable);
myThread.start();
3 голосов
/ 20 сентября 2008

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

2 голосов
/ 20 сентября 2008

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

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...