Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java: Why does this not get garbage collected?

Quick question about the theory of GCing. I have the following method. It runs, and exits the method. How come even after GC is run, the timer still exists and keeps "TICK"ing? I don't believe there's still a reference to timer or the timertask anymore after this method exists, so I'd expect the timer to be GCed and cause an exception. Please help me understand this concept.

Thanks, 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);     } 
like image 393
jbu Avatar asked Apr 20 '09 17:04

jbu


People also ask

Does Java automatically collect garbage?

Java garbage collection is an automatic process. The programmer does not need to explicitly mark objects to be deleted. The garbage collection implementation lives in the JVM. Each JVM can implement garbage collection however it pleases; the only requirement is that it meets the JVM specification.

Can you force JVM to do garbage collection?

You really can't force Java GC. The Java garbage collection algos are non-deterministic, and while all of these methods can motivate the JVM to do GC, you can't actually force it.

Why are unreachable objects not garbage collected?

There are several aspects in the behaviour you are facing. First and foremost, having unreachable objects inside heap at any given time is perfectly normal. Garbage Collection will clean the unreachable objects during the next run and will clean the heap from them.


2 Answers

The Timer object actually schedules tasks to be executed in a background thread, so that background thread maintains a reference to the Timer (and the TimerTask), which prevents both from being garbage-collected.

Here is the appropriate quote from the docs:

After the last live reference to a Timer object goes away and all outstanding tasks have completed execution, the timer's task execution thread terminates gracefully (and becomes subject to garbage collection). However, this can take arbitrarily long to occur. By default, the task execution thread does not run as a daemon thread, so it is capable of keeping an application from terminating. If a caller wants to terminate a timer's task execution thread rapidly, the caller should invoke the the timer's cancel method.

So the condition that "all outstanding tasks have completed execution" is not satisfied, and the thread never terminates, so the Timer/TimerTask is never GC'd.

like image 162
Rick Copeland Avatar answered Oct 16 '22 15:10

Rick Copeland


Because a Timer has a background thread that continues running:

Corresponding to each Timer object is a single background thread that is used to execute all of the timer's tasks, sequentially. Timer tasks should complete quickly. If a timer task takes excessive time to complete, it "hogs" the timer's task execution thread. This can, in turn, delay the execution of subsequent tasks, which may "bunch up" and execute in rapid succession when (and if) the offending task finally completes.

Since it's a background thread, it continues until the JVM exits or it's stopped.

Update: a little more on this. A "background thread" is the same thing as a daemon thread -- named by analogy with a BSD daemon process. If you see the javadocs on Thread, you'll find:

Marks this thread as either a daemon thread or a user thread. The Java Virtual Machine exits when the only threads running are all daemon threads.

When your main terminates, all the user threads stop, leaving only daemon threads. The JVM then shuts down. For a good time — if short — call Thread.currentThread().setDaemon(true); from main.

Update: Ack. I had that almost right. You have to make the timer a daemon at construction time. (Did this change, or did I just have a brain failure?)

Anyway, here's example code:

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 ;     } } 
like image 45
Charlie Martin Avatar answered Oct 16 '22 17:10

Charlie Martin