我的 Main() 方法如何保存对已释放且不再使用的变量的引用?



我正在努力修复一个大型项目中的内存泄漏,因此我将其缩小为一个 Main() 方法,其中引用类型对象Obj1包含对另一个引用类型对象的引用Obj2。然后,我创建另一个类型为Obj1的对象,其中包含对同一Obj2对象的引用。这两个对象都在自己的使用块中,如下所示:

using (dynamic obj1_a = new Obj1(args)) 
{
do some actions...
using (dynamic obj1_b = new Obj1(args))
{
do some more actions...
//Memory Snapshot 1 taken here
}
}
GC.Collect();
GC.WaitForPendingFinalizer();
GC.Collect();
//Memory Snapshot 2 taken here

不知何故,当我在上面评论的点拍摄 2 个快照并进行比较时,.NET 内存探查器表明,即使两个对象obj1_aobj1_b已被释放,它们也没有被 GC 处理。当我检查引用图时,我看到内存分析器说这两个对象都是由我的 Main() 方法本身引用的。我已经浏览了 Main() 方法的整个代码(它不是很复杂,只是创建、稍微修改然后测试垃圾收集),看看这两个对象是否还有变量引用,但没有。我的 Main() 方法怎么可能将这些对象保存在内存中?重要的是,它们被垃圾回收(或者至少能够得到GC'ed),因为它们包含对更多引用和值类型的引用,如果没有它,程序就会变得相当内存消耗。

即使

obj1_a和obj1_b两个对象已被释放,它们也没有被GC化

您的语句预先假定要释放的对象与垃圾回收器解除分配的对象之间存在连接。确保您完全理解以下声明:处置对象对它是否有资格被收集没有任何影响。从GC的角度来看,Dispose只是一种方法。你不妨说"即使我在对象上调用了ToString,它仍然没有被GC'd"。ToString与GC有什么关系?无。Dispose与GC有什么关系?什么都没有

现在,这有点夸大了情况。可完成的对象应实现 IDisposable,其 Dispose 应调用 SuppressFinalization。这对垃圾回收器有影响,因为可终结对象的生存时间始终至少比它们长一个集合,因为终结队列是根。但这里的效果不是直接归因于Dispose;它只是处理器抑制最终确定的约定。抑制对GC行为有影响。

我的 Main() 方法怎么可能将这些对象保存在内存中?

当 GC 确定没有包含对该对象的直接或间接引用的活动根时,GC 会收集该对象。

活动方法中的局部变量是活动根。

允许运行时完全自行决定并出于任何原因 (1) 确定永远不会再次读取局部变量并将其视为早期死亡,以及 (2) 即使控制已超出该变量的局部变量声明空间,也允许局部保持更长时间的活动。

即使您的obj1_aobj1_b在 GC 运行时超出范围,运行时也完全允许假装它们已在Main的最高范围内声明,并允许它们保持活动状态,直到Main完成,即 GC 运行之后

重要的是,它们被垃圾回收(或者至少能够得到GC'ed),因为它们包含对更多引用和值类型的引用,如果没有它,程序就会变得相当内存消耗。

如果您需要对对象的生存期进行细粒度控制,那么具有自动内存释放功能的语言将无法满足您的要求

最新更新