【发布时间】:2018-11-09 16:16:09
【问题描述】:
我已经编写了简单的测试程序:
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 个对象。
【问题讨论】:
-
调试或发布版本?
-
调试,.Net 4.5
-
在调试版本中,或者如果你连接了调试器,变量的生命周期,甚至是编译器生成的临时变量,都会延长到方法的末尾,以方便断点和检查变量不再使用的方法。切换到发布版本并重试。
-
我已切换到发布配置。现在在初始化 a1-a5 变量后,VS 显示'堆中有 15 个对象,分配 null 后仍然保留 14 个 A 实例。
-
那么你用来查找这些对象的工具可能就像一个调试器。程序集中有元数据(如果我没记错的话)标识变量被认为“正在使用”的方法代码的跨度,这个跨度在最后一次写入或读取后停止。如果代码在 这样的跨度之后执行,则该变量被认为是死的,并且应该忽略它是否具有引用,但是当存在调试器时这些跨度会被扩展,因此该工具可能是表现得像一个人,这让我们一团糟。
标签: c# .net garbage-collection