24

Possible Duplicate:
Java Thread Garbage collected or not

Consider the following class:

class Foo implements Runnable {

  public Foo () {
       Thread th = new Thread (this);
       th.start();
  }

  public run() {
    ... // long task
  }

}

If we create several instances of Foo by doing

new Foo();
new Foo();
new Foo();
new Foo();

(note that we don't keep a pointer to them).

  1. Could those instances be removed by the garbage collector before the thread in run() ends? (In other words: is there any reference to the Foo objects?)

  2. And, in the other hand, will those instances be removed by the GC after the thread in `run()' ends, or are we wasting memory ("memory leak")?

  3. If either 1. or 2. are a problem, what's the right way to do it?

Thanks

4
  • You can actually test this very easily. Commented Apr 30, 2012 at 8:50
  • @Quaternion, yes maybe, but the wording of that other question is really "obfuscated" and hard to understand, imho. Commented Apr 30, 2012 at 9:00
  • 1
    This is not a duplicate. The linked question does not address the aspect of "will it be garbage collected at all after completing" (I was about to ask this specifically). It only asks/answers the aspect of "it will not be GC'ed while running". This question here is in my opinion better. Commented Aug 30, 2014 at 8:55
  • 1
    That is what happens when you gamify content-policing. Stuff gets marked as duplicate when it's clearly not. Commented Nov 9, 2015 at 16:43

5 Answers 5

23
  1. Any object which is referenced by an active thread may not be de-allocated.
  2. Yes, instances will be removed by the GC after the thread in `run()' ends.
  3. No prob.
Sign up to request clarification or add additional context in comments.

1 Comment

Please give me where you get this this conclusion.
12
  1. Could those instances be removed by the garbage collector before the thread in run() ends? (In other words: is there any reference to the Foo objects?)

No. While the constructor is running GC won't collect the object. Otherwise even the simplest:

Customer c = new Customer();

could fail while the constructor of Customer is running. On the other hand when you start a new thread, the thread object becomes a new GC root, so everything referenced by that object is not a subject to garbage collection.

  1. And, in the other hand, will those instances be removed by the GC after the thread in `run()' ends, or are we wasting memory ("memory leak")?

Once the thread is done, it is no longer a GC root. If no other code points to that thread object, it will be garbage collected.

  1. If either 1. or 2. are a problem, what's the right way to do it?

Your code is just fine. However:

  • starting a new thread in a constructor is a poor idea from unit-testing point of view

  • keeping a reference to all running thread might be beneficial if e.g. you want to interrupt these threads later.

2 Comments

@MarkoTopolnik: oh, it does! OP is passing this to Thread constructor which happens to be an instance of Foo. This is however correct - if Foo has some state, all state variables will survive GC because they are referenced by Foo - and Foo is referenced by the thread itself.
Starting a new thread in a constructor is a poor idea from a thread safety point of view too. In this simple case, there is likely problem, but if you subclassed the class and initialised some final fields in the subclass constructor, you could end up with them not being initialised before being accessed.
8

Starting a new thread without specifying a thread group will add it to the default group:

If group is null and there is a security manager, the group is determined by the security manager's getThreadGroup method. If group is null and there is not a security manager, or the security manager's getThreadGroup method returns null, the group is set to be the same ThreadGroup as the thread that is creating the new thread.

The group will keep a reference to the thread as long as it is alive, so it can't be GC'd during that time.

When a thread terminates (= when run() returns for whatever reason), the thread is removed from the thread group. This happens in the private method exit() which is called from native code. This is the point in time when the last reference to the thread is lost and it becomes eligible for GC.

Note that the code indicates that ThreadGroup can be null but that isn't the case. The various null-checks are just to avoid NPEs in the rare case that something goes wrong. In Thread.init(), you would get NPEs if Java couldn't determine a thread group.

2 Comments

And what if we create a new ThreadGroup (whose parent is the default ThreadGroup) for all Threads created in the Foo class? Will it make any difference in GC behavior? Specifically when the class instance who created Foo objects gets GCed, but the created Threads are still running.
@IrfanLatif As long as the thread keep a pointer to the Foo instance which started it (by passing this), the instance will only get GCed after the thread has terminated AND there are no other references to this Foo instance. It doesn't matter how complicated the reference chain gets. A ThreadGroup is nothing special as far as GC is concerned. Threads only affect things like synchronization.
3
  1. The Foo object is referenced by the Thread. Thread is referenced during its run all the time. Therefore it will not be garbage collected.
  2. No memory leaks. Thread will end and will be garbage collected and Foo object in this process as well.
  3. It should work fine.

Comments

0

Assuming you are creating the objects in the run method, the objects will go out of scope when the run method exits and then will be available for garbage collection. Run is just another method. Using threads or not does not change the garbage collection behavior here in any way. All you need to care about is when the objects go out of scope, which is generally tied to block scope (method block, while loop, if block, etc..).

So, since you are not keeping any reference to the object to begin with, you might want to extract the logic that creates the object into its own short lived method. That way the object that is created won't need to be kept beyond the scope of that method.

2 Comments

the Foo objects are create not int the run method, but, for instance, in main.
just another code block, doesn't change a thing

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.