我编写了简单的测试程序:
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实例,正如预期的那样:
但是在变量 a1-a5 变为等于 null 后,即使在额外调用 GC.Collect 方法之后,堆中仍然包含 A 实例。并且更多的GC.Collect调用不会减少堆中的A对象。为什么?有没有办法强制收集所有未使用的对象?
编辑: 我已切换到 Release 配置,在初始化 a1-a5 变量后,我看到堆中有 15 个对象:
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/