c# - .Net 为什么GC不从堆中删除对象?

标签 c# .net garbage-collection

我编写了简单的测试程序:

namespace GCTest {
class Program {
    static void Main(string[] args) {
        var a1 = new A();
        a1.AProperty = new A();
        a1.AProperty.AProperty = new A();
        a1.AProperty.AProperty.AProperty = new A();
        a1.AProperty.AProperty.AProperty.AProperty = new A();
        Console.WriteLine("a1 created");
        Console.ReadKey();

        var a2 = new A();
        a2.AProperty = new A();
        a2.AProperty.AProperty = new A();
        a2.AProperty.AProperty.AProperty = new A();
        a2.AProperty.AProperty.AProperty.AProperty = new A();
        Console.WriteLine("a2 created");
        Console.ReadKey();

        var a3 = new A();
        a3.AProperty = new A();
        a3.AProperty.AProperty = new A();
        a3.AProperty.AProperty.AProperty = new A();
        a3.AProperty.AProperty.AProperty.AProperty = new A();
        Console.WriteLine("a3 created");
        Console.ReadKey();

        var a4 = new A();
        a4.AProperty = new A();
        a4.AProperty.AProperty = new A();
        a4.AProperty.AProperty.AProperty = new A();
        a4.AProperty.AProperty.AProperty.AProperty = new A();
        Console.WriteLine("a4 created");
        Console.ReadKey();

        var a5 = new A();
        a5.AProperty = new A();
        a5.AProperty.AProperty = new A();
        a5.AProperty.AProperty.AProperty = new A();
        a5.AProperty.AProperty.AProperty.AProperty = new A();

        Console.WriteLine("a5 created");
        int a1Gen = GC.GetGeneration(a1);
        Console.WriteLine("a1 generation: " + a1Gen);
        GC.Collect();
        GC.WaitForPendingFinalizers();
        a1Gen = GC.GetGeneration(a1);
        Console.WriteLine("a1 generation: " + a1Gen);
        GC.Collect();
        GC.WaitForPendingFinalizers();
        a1Gen = GC.GetGeneration(a1);
        Console.WriteLine("a1 generation: " + a1Gen);
        GC.Collect();
        GC.WaitForPendingFinalizers();
        a1Gen = GC.GetGeneration(a1);
        Console.WriteLine("a1 generation: " + a1Gen);
        Console.ReadKey();

        a1 = a2 = a3 = a4 = a5 = null;
        Console.WriteLine("a1-a5 are null");
        Console.ReadKey();

        Console.WriteLine("GC");
        GC.Collect(2, GCCollectionMode.Forced);
        GC.WaitForPendingFinalizers();
        Console.ReadKey();

        Console.WriteLine("GC");
        GC.Collect(2, GCCollectionMode.Forced);
        GC.WaitForPendingFinalizers();
        Console.ReadKey();

        Console.WriteLine("GC");
        GC.Collect(2, GCCollectionMode.Forced);
        GC.WaitForPendingFinalizers();
        Console.ReadKey();

        Console.WriteLine("GC");
        GC.Collect(2, GCCollectionMode.Forced);
        GC.WaitForPendingFinalizers();
        Console.ReadKey();
    }
}

class A {
    int[] arr = new int[1000];
    public A() {
        arr[0] = 1;
    }

    public A AProperty { get; set; }
}

}

我使用内置的 Visual Studio 2017 诊断工具制作快照。 当a1 - a5变量初始化时,堆中有25个A实例,正如预期的那样:

enter image description here

但是在变量 a1-a5 变为等于 null 后,即使在额外调用 GC.Collect 方法之后,堆中仍然包含 A 实例。并且更多的GC.Collect调用不会减少堆中的A对象。为什么?有没有办法强制收集所有未使用的对象?

enter image description here

编辑: 我已切换到 Release 配置,在初始化 a1-a5 变量后,我看到堆中有 15 个对象:

enter image description here

GC.Collect 调用后仍然保留 14 个对象。

最佳答案

我不知道 VS 如何处理这个问题,但如果我使用发布版本运行您的代码,则在使用 SOS 检查它时,我在堆上看不到任何 A 实例。

亲自看看,download WinDbg 。然后附加到您的进程并加载 SOS。

.loadby sos clr

您可以使用 !dumpheap -stat 转储整个堆,或者使用 !dumpheap -type GCTest.A 仅转储类型。

您应该会看到实例在创建时不断增加。一旦 GC 回收了实例,您就不应该在堆上看到任何 A 实例。

这是在所有引用都清空后第一次 GC 后的输出。

0:001> !dumpheap -type GCTest.A
 Address       MT     Size

Statistics:
      MT    Count    TotalSize Class Name
Total 0 objects

关于c# - .Net 为什么GC不从堆中删除对象?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53221550/

相关文章:

c# - 阻塞 ForEach 直到异步事件完成

c# - 当我完成 View 和 ViewModel 而不是 Model 时,如何删除事件处理程序

c# - C# 方法中的互斥体初始化总是返回正的 createdNew

c# - 从mp3文件中删除特定的频率

c# - 查看和模型数据格式

.net - 如何在域相关的 .NET Core 中更改/创建自定义 FileProvider(即一个 Web 应用程序为多个站点呈现逻辑提供服务)

c# - 如何获取 JSON 字符串值?

.net - async void 方法不立即返回 (EF6)

c# - C#'s ` yield return` 为我制造了很多垃圾。有救吗?

java - JVM 如何实现 IdentityHashMap?