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

Community
  • 1
  • 1
cibercitizen1
  • 20,944
  • 16
  • 72
  • 95
  • You can actually test this very easily. – Radu Murzea Apr 30 '12 at 08:50
  • @Quaternion, yes maybe, but the wording of that other question is really "obfuscated" and hard to understand, imho. – cibercitizen1 Apr 30 '12 at 09: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. – bluenote10 Aug 30 '14 at 08:55
  • 1
    That is what happens when you gamify content-policing. Stuff gets marked as duplicate when it's clearly not. – Joseph Persico Nov 09 '15 at 16:43

5 Answers5

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.
Luca
  • 4,223
  • 1
  • 21
  • 24
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.

Tomasz Nurkiewicz
  • 334,321
  • 69
  • 703
  • 674
  • @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. – Tomasz Nurkiewicz Apr 30 '12 at 08:17
  • 4
    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. – Bill Michell Apr 30 '12 at 08:21
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.

Aaron Digulla
  • 321,842
  • 108
  • 597
  • 820
  • And what if we create a new `ThreadGroup` (whose parent is the default `ThreadGroup`) for all `Thread`s 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 `Thread`s are still running. – Irfan Latif Dec 27 '21 at 13:24
  • @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. – Aaron Digulla Jan 13 '22 at 20:41
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.
Ondrej Peterka
  • 3,349
  • 4
  • 35
  • 49
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.

Jilles van Gurp
  • 7,927
  • 4
  • 38
  • 46