Подтвердить что ты не робот

Java: Почему это не получает сбор мусора?

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

Спасибо, 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);
    }
4b9b3361

Ответ 1

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

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

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

Итак, условие, что "все невыполнимые задачи завершены" не выполнено, и поток никогда не заканчивается, поэтому Timer/TimerTask никогда не GC'd.

Ответ 2

Поскольку таймер имеет фоновый поток который продолжает работать:

Соответственно каждому объекту 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 ;
    }
}

Ответ 3

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

Ответ 4

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