C# 收集仍在作用域中的对象-GC.Collect

C# 收集仍在作用域中的对象-GC.Collect,c#,.net,garbage-collection,C#,.net,Garbage Collection,我读过这篇文章:老实说,我不了解每一个细节。据我所知,在下面的代码中,即使我没有将c设置为null,也应该收集c。另一件事是,只要我们在同一个函数的范围内,foreach期间发生的分配似乎就不会被释放。(见下面的示例) 编辑第一个示例的解决方案:调试模式(不是在调试器中运行,而是在编译模式下运行)。如果我使用Release,它将按预期工作:即使没有设置为null,也会收集c。第二个例子也是如此 第二个例子 static void Main(string[] args) { Console

我读过这篇文章:老实说,我不了解每一个细节。据我所知,在下面的代码中,即使我没有将c设置为null,也应该收集c。另一件事是,只要我们在同一个函数的范围内,foreach期间发生的分配似乎就不会被释放。(见下面的示例)

编辑第一个示例的解决方案:调试模式(不是在调试器中运行,而是在编译模式下运行)。如果我使用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 提取(收集):5594308 浏览人数:272553096 穿越(收集):269564660 收款:269564048


如果我把foreach循环放在另一个函数中并调用这个函数,那么在.Collect is调用之后使用的内存大约是5800000。那么,当我在同一个函数中使用foreach循环时,为什么不收集垃圾呢?

garbace收集器的行为是不确定的,不应该被认为是确定的。不要依赖GC


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

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

事实上,对于可调试代码,JIT 将每个变量的生存期延长到 函数结束


因此,您的集合不会像您发现的那样在调试模式下被收集,以及为什么它会在发布模式下被收集。

这是不确定的,但您可以强制一个集合,该集合将尝试收集未使用的对象。GetTotalMemory(true)等待当前集合完成。因此,至少应该释放一些数据。每次尝试的大小不一样是可以的,但是200MB的差异不是预期的…@Malone,这是不确定的。所以“至少应该释放一些数据”这句话不适用。为了能够说它必须是确定性的。
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();
}