收集仍在范围内的对象 – GC.Collect

我读过这篇文章: http : //blogs.msdn.com/b/oldnewthing/archive/2010/08/10/10048149.aspx老实说我并不了解每一个细节。 据我所知,在下面的代码中,即使我没有将c设置为null,也应该收集c。 另一件事是,只要我们处于同一函数的范围内,在foreach期间发生的分配似乎不会被释放。 (见下面的例子)

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 * */ } } 

编辑第一个示例的解决方案:调试模式(不在调试器中运行,但甚至在编译模式下运行)。 如果我使用Release它将按预期工作:即使没有设置为null也会收集c。 对于第二个例子,同样适用。

第二个例子

 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(); } 

输出:

启动记忆:193060获取:8972464取(collections):5594308已穿越:272553096已穿越(collections):269564660已收:269564048

如果我将foreach循环放在另一个函数中并调用此函数,则.Collect调用后使用的内存大约为5800000.那么为什么在同一函数中使用foreach循环时不会收集垃圾?

在Raymond的文章和Yun Jin的MSDN文章的评论中提到过

事实上,对于可调试代码,JIT将每个变量的生命周期延长到函数的末尾。

因此,您的集合将不会在您发现的调试模式下收集,也不会在发布模式下收集它。

Garbacecollections家的行为不是确定性的,不应该被认为是确定性的。 不要依赖GC。

您在问为什么GC 不会在给定时间点收集您的垃圾。 更好的问题是为什么它在给定时间点的收集。