Folks,
If I set a large object to .net to null in the middle of a long-running method (not necessarily CPU intensive...just long-running) is it immediately game for garbage collection OR does the method need to complete before the object is ready for garbage collection?
The method doesn't need to complete, but neither do you need to set the variable to null, if the GC can tell you're not going to read from it again. For example:
public void Foo()
{
SomeObject x = new SomeObject();
// Code which uses x
Console.WriteLine("Eligible for collection");
// Code which doesn't use x.
}
The object is eligible for collection at the indicated point - assuming nothing else has kept a reference to it, of course. The important thing is whether anything is ever going to be able to read that value again. You can even assign the variable a different value and then read it, and so long as the GC knows that it won't see the original value again, that won't act as a GC root. For example:
using System;
class Bomb
{
readonly string name;
public Bomb(string name)
{
this.name = name;
}
~Bomb()
{
Console.WriteLine(name + " - going boom!");
}
public override string ToString()
{
return name;
}
}
class Test
{
static void Main()
{
Bomb b = new Bomb("First bomb");
Console.WriteLine("Using bomb...");
Console.WriteLine(b);
Console.WriteLine("Not using it any more");
GC.Collect();
GC.WaitForPendingFinalizers();
Console.WriteLine("Creating second bomb...");
b = new Bomb("Second bomb");
Console.WriteLine("Using second bomb...");
Console.WriteLine(b);
Console.WriteLine("End of main");
}
}
Output:
Using bomb...
First bomb
Not using it any more
First bomb - going boom!
Creating second bomb...
Using second bomb...
Second bomb
End of main
Second bomb - going boom!
In fact, it can get more extreme than that: an object can be eligible for garbage collection even while a method is running "in" it so long as the GC can detect that nothing can ever read a field again. Here's a short but complete example:
using System;
class Bomb
{
int x = 10;
~Bomb()
{
Console.WriteLine("Boom!");
}
public void GoBang()
{
Console.WriteLine("Start of GoBang");
GC.Collect();
GC.WaitForPendingFinalizers();
Console.WriteLine("x={0}", x);
Console.WriteLine("No more reads of x");
GC.Collect();
GC.WaitForPendingFinalizers();
Console.WriteLine("Returning");
}
}
class Test
{
static void Main()
{
Bomb b = new Bomb();
b.GoBang();
Console.WriteLine("Still in Main");
}
}
Output:
Start of GoBang
x=10
No more reads of x
Boom!
Returning
Still in Main
(Run this not in the debugger - the debugger delays garbage collection so that you can still watch variables.)
One point to note: your question talks about setting an object to null... that concept doesn't exist. You only ever set a variable to null. It's worth distinguishing between the two.
See Raymond Chen's article When does an object become available for garbage collection?. Basically, it can be eligible for collection at almost any time, including even before you set that reference to null
.
Scope does not really matter, though, as that's only a compiler thing to determine where a given name is visible. It doesn't have anything to do with the lifetime of objects.
Assuming that the previously-held value is no longer referenced by anything, it is immediately eligible for garbage collection.