Reputation: 2763
I have read this article: https://devblogs.microsoft.com/oldnewthing/20100810-00/?p=13193 and honestly I don't understand every detail. As far as I understand in the code below c
should be collected even if I don't set c
to null
. Another thing is that allocations happening during a foreach
seem to be not freed as long as we in the scope of the same function. (See example below)
class Program
{
public class SomeClass
{
public byte[] X;
public SomeClass()
{
X = new byte[1024 * 1024 * 100];
X[155] = 10;
}
}
static void Main()
{
Console.WriteLine("Memory: " + GC.GetTotalMemory(false));
SomeClass c;
c = new SomeClass();
Console.WriteLine("Memory: " + GC.GetTotalMemory(false));
GC.Collect();
Console.WriteLine("Memory: " + GC.GetTotalMemory(true));
Console.ReadKey();
/* Output:
*
* Memory: 186836
* Memory: 105044468
* Memory: 104963676
*/
}
}
EDIT The solution for the first example: The Debug-Mode (not running in debugger but even the compilation-mode). If I use Release it'll work as expected: c
is collected even without setting to null
. For Second example the same applies.
Second example
static void Main(string[] args)
{
Console.WriteLine("Startup Memory: " + GC.GetTotalMemory(false));
var obj = BOObject.Get();
Console.WriteLine("Fetched Object: " + GC.GetTotalMemory(false));
GC.Collect();
Console.WriteLine("Fetched Object (Collected): " + GC.GetTotalMemory(false));
foreach (var node in obj.Traverse())
{
string name = node.Name;
}
Console.WriteLine("Traversed: " + GC.GetTotalMemory(false));
GC.Collect();
Console.WriteLine("Traversed (collected): " + GC.GetTotalMemory(false));
obj = null;
GC.Collect();
Console.WriteLine("collected: " + GC.GetTotalMemory(true));
Console.Read();
}
Output:
Startup Memory: 193060
Fetched: 8972464
Fetched (Collected): 5594308
Traversed: 272553096
Traversed (collected): 269564660
collected: 269564048
If I put the foreach
loop in another function and call this function, the memory used after .Collect
is called is about 5800000. So why the garbage is not collected when I have the foreach
loop in the same function?
Upvotes: 6
Views: 1224
Reputation: 7592
Mentioned in the comments to Raymond's article and in Yun Jin's MSDN article here that
In fact, for debuggable code, JIT extends lifetime for every variable to end of the function.
Therefore your collection won't be collected in Debug mode as you discovered and why it will be collected in Release mode.
Upvotes: 9
Reputation: 11750
The garbace collector's behaviour is not deterministic and should not be expected to be deterministic. Don't rely on the GC.
You are asking why the GC is not collecting your garbage at a given point in time. The better question would be why it is collection at a given point in time.
Upvotes: 0