2009-04-20 3 views
19

Быстрый вопрос о теории GCing. У меня есть следующий метод. Он запускается и выходит из метода. Почему даже после того, как GC запущен, таймер все еще существует и сохраняет «TICK»? Я не верю, что после этого метода все еще есть ссылка на таймер или таймер, поэтому я ожидаю, что таймер будет GCed и вызовет исключение. Пожалуйста, помогите мне понять эту концепцию.Java: Почему это не получает сбор мусора?

Спасибо, JBU

private void startTimer() 
    { 
     Timer timer= new Timer(); 
     TimerTask timerTask= new TimerTask() 
     { 

      @Override 
      public void run() 
      { 
       System.out.println("TICK"); 
      } 
     }; 

     timer.scheduleAtFixedRate(timerTask, 
       0, 
       500); 
    } 
+0

Не было бы ужасно, если это действительно уйти? Это сделало бы почти все многозадачные задачи более сложными. –

ответ

0

Как вы знаете GC побежал? Сбор мусора вообще не является детерминированной вещью, и это определенно не вызвано сферой применения метода. Это не похоже на C++, где вы оставляете область действия и уничтожения деструкторов. Он будет собираться, чтобы собрать эту память, если и когда GC это понравится.

+1

Я вызвал GC напрямую через режим отладки netbeans. – jbu

33

Объект Timer фактически задает задачи, которые должны выполняться в фоновом потоке, так что фоновый поток поддерживает ссылку на таймер (и TimerTask), который предотвращает сбор мусора.

Вот соответствующая цитата из документации:

После последней живой ссылки на объект таймера уходит, и все выдающихся задачи выполнили выполнение, выполнение задачи потока таймера включения завершается корректно (и становится объектом мусора сбор). Однако это может занять произвольно долго. По умолчанию поток выполнения задачи не запускается в качестве потока демона, поэтому он способен сохранить приложение с . Если вызывающий абонент хочет, чтобы прекратил выполнение задачи таймера поток, вызывающий должен вызвать метод отмены таймера.

Таким образом, условие «выполнение всех невыполненных задач выполнено» не выполняется, и поток никогда не заканчивается, поэтому Timer/TimerTask никогда не GC'd.

+0

Точно. Из JavaDocs Timer: «Соответствие каждому объекту Timer - это один фоновый поток, который используется для выполнения всех задач таймера последовательно». –

+0

Однако, если я отменил Таймер, таймер/TimerTask в конечном итоге будет GC'ed? – ptikobj

2

Таймер не собирает мусор, потому что он все еще работает. В другом объекте (например, планировщик потоков) есть ссылка на него, которая, вероятно, была создана внутри scheduleAtFixedRate().

12

Поскольку таймер имеет background thread that continues running:

В соответствии с каждым объектом Timer является один фоновый поток, который используется для выполнения всех задач таймера последовательно. Задачи таймера должны быть выполнены быстро. Если задание таймера занимает слишком много времени, он «свирепствует» выполнение задачи таймера нить. Это может, в свою очередь, задержать выполнение последующих задач, которые может «сгруппироваться» и выполнить в быстрой последовательности , когда (и если) завершающая задача , наконец, завершается.

Поскольку это фоновый поток, он продолжается до выхода JVM или его остановки.

Обновление: немного больше об этом. «Фоновый поток» - это то же самое, что и поток демона, названный по аналогии с процессом демона BSD. Если вы видите Javadocs на Thread, вы найдете:

маркирует эту нить или как демон нить или нить пользователя. Виртуальная машина Java завершает работу только в тех потоках, в которых работает только , всех демонов .

Когда ваш главный абонент останавливается, все пользовательские потоки останавливаются, оставляя только потоки демона. Затем JVM выключается. Хорошо провести время - если коротко позвонить Thread.currentThread().setDaemon(true); с основного.

Обновление: Ack. У меня было это почти справа. Вы должны сделать таймер демоном во время строительства. (Ли это изменение, или же я просто отказ мозга?)

Во всяком случае, вот пример кода:

import java.util.*; 

class Chatter extends TimerTask { 
    public void run(){ 
     System.err.println("Timer run."); 
    } 
} 

public class TryThread { 
    public static void main(String[] argv){ 
     // If argument is true, only runs a few times. 
     Timer t = new Timer(false); 
     t.schedule(new Chatter(), 1L, 1L); 
     return ; 
    } 
} 
+2

Просто, чтобы подчеркнуть точку Чарли, живые потоки являются «корневыми» объектами для сборщика мусора. Они не мусор, пока они не умрут и не могут быть собраны. Все, что сильно ссылается на живую нить, тоже не мусор. Занятые классы работают аналогичным образом. – erickson

+0

Подождите, так что этот таймер может продолжить выполнение даже после того, как программа, которая его вызвала, заканчивается? –

+0

Нет, потому что, когда публичная статическая void main, которая была вызвана в начале, заканчивается, JVM полностью отключается, что означает остановку и уничтожение фоновых потоков. На самом деле это не GC, а потому, что когда процесс умирает, вся память освобождается. –

Смежные вопросы