20

I have the following code:

new Thread(new ThreadStart(delegate()
{
    while (true)
    {
        //something
    }
})).Start();

Can garbage collector finalize this instance of Thread while it is in the Running state?

Adam Zalcman
  • 26,643
  • 4
  • 71
  • 92
Svisstack
  • 16,203
  • 6
  • 66
  • 100

4 Answers4

26

The CLR keeps track of all running threads. As long as there are references to objects they won't be garbage collected. And since the CLR keeps a reference to all running threads the GC won't touch them.

Darin Dimitrov
  • 1,023,142
  • 271
  • 3,287
  • 2,928
15

No; running threads count as roots. A running thread will not be collected, nor will anything referenced by the active part(s) of the stack for that thread.

Marc Gravell
  • 1,026,079
  • 266
  • 2,566
  • 2,900
  • _running threads count as roots?_ or _references (inside a threads) which reference to objects count as roots.._ ? – Royi Namir Mar 08 '14 at 09:32
  • 1
    @Royi roots - basically, the stack locals. Note that arg0 (aka this) will usually keep the target instance alive too – Marc Gravell Mar 08 '14 at 12:35
  • So is it wrong/ok to say : _GC is not allowed to collect a running thread_ ? – Royi Namir Mar 08 '14 at 13:04
  • @Royi well, an actual thread isn't a managed object in the first place. The `Thread` type is mainly a utility to help talk to the CLI thread, which sometimes is and sometimes isn't a 1:1 map to an OS thread (sql server being an example of "isnt"). – Marc Gravell Mar 08 '14 at 17:32
  • Sorry , i was talking about managed one . Does gc allow to collect that thread if it has no roots inside it ? – Royi Namir Mar 08 '14 at 18:04
  • 1
    @Royi that doesn't make sense. The only managed thing here is the `Thread`, but that is not the *thread*. The `Thread` doesn't have things "inside it" as such. The *thread*, however, is a root - and is not collectable. Whether the `Thread` is collectable would be an implementation detail. – Marc Gravell Mar 08 '14 at 18:18
3

The thread won't be collected, because each running, waiting or suspended thread is itself used by the GC to decide what is alive (trace everything in every thread's stack, trace everything referenced by all of those objects, then everything referenced by those, and so on, and you've identified everything that can't be garbage collected).

The thread could end, if it was a background thread, because then it'll be actively shut down when all other threads in the process finish. Otherwise the only thing that'll cause it to die is the process being actively exited, an exception (including ThreadAbortException) or it breaking out of the while loop itself.

There's a case that's comparable in some ways, that may be what you are thinking of:

var timer = new System.Threading.Timer(someCallback, null, new TimeSpan(0, 0, 5), new TimeSpan(0, 0, 5));
int someResult = doingSomethingElse();
doSomethingElseThatTakesLongerThan5Seconds();

This is another piece of code that causes another thread of execution to do something. In this case, the timer can indeed be garbage collected before the run, during one of the runs, or pretty much any time after the constructor returns.

The important thing here is that there isn't an individual thread for the timer, and the thread doesn't even "know" about the timer object. Since the last access of the object has since happened, it's eligible for collection. This is different to the matter of an individual thread that is running (or waiting, etc.).

Jon Hanna
  • 110,372
  • 10
  • 146
  • 251
1

All running timer, threads, thread pool and tasks are marked as root. So they will be garbage collected only when they're done (finished executing) or will be deleted when the application closes.

polinens
  • 11
  • 2