我的Main()方法如何保存对已经处理且不再使用的变量的引用? [英] How can my Main() method be holding references to variables that have been disposed and are no longer used?

查看:287
本文介绍了我的Main()方法如何保存对已经处理且不再使用的变量的引用?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

  using(dynamic obj1_a = new Obj1(args))
{
做一些动作...
使用(动态obj1_b = new Obj1(args))
{
做更多的动作...
/ / Memory Snapshot 1 take here
}
}
GC.Collect();
GC.WaitForPendingFinalizer();
GC.Collect();
//在此存储的快照2

不知何故,当我拍摄2张快照时点评论上面并比较它们,.NET Memory Profiler指出即使已经处理了两个对象 obj1_a obj1_b ,他们没有被GC'ed。当我检查参考图时,我发现内存分析器说这两个对象都是由我的Main()方法本身引用的。我已经浏览了Main()方法的全部代码(它不是很复杂,只是创建,稍微修改然后测试垃圾收集),以查看是否存在针对这两个对象的变量引用,但没有。我的Main()方法可能将这些对象保存在内存中又如何?重要的是,他们会收集垃圾(或者至少能够获得GC),因为它们包含对更多参考和值类型的引用,并且程序在没有它的情况下变得相当耗费内存。

解决方案

即使两个对象obj1_a和obj1_b已被处置,它们也没有被GC 'ed

你的语句预设了一个对象被释放并被垃圾收集器解除分配。确保您完全理解以下声明:处置对象对于是否有资格收集无关紧要。从GC的角度来看, Dispose 只是一种方法。你可能会说即使我在对象上调用了 ToString ,它仍然没有被GC'd。 ToString 与GC有什么关系?没有。 Dispose 与GC有什么关系? 什么都不是



现在,这略微夸大了情况。可终结对象应该实现IDisposable,其Dispose应该调用SuppressFinalization。这对垃圾回收器有影响,因为可终结对象始终至少存在一个比它们更长的集合,因为最终化队列是根。但这里的效果并不是直接导致 Dispose ;这简直就是垃圾处理者压制敲定的惯例。这是对GC行为有影响的压制。


我的Main()方法如何保持这些对象在内存中?


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



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



运行时允许完全在(1)确定本地永远不会再被读取,并将其视为死亡,并且(2)保持本地活着更长 obj1_a 和 code> obj1_b 在GC运行时超出范围,运行时完全被允许假装它们被声明在 Main ,并允许它们保持活动状态,直到 Main 完成,这是在GC运行之后。


重要的是它们会收集垃圾(或者至少可以获取GC),因为它们包含对更多参考和值类型的引用,并且程序变得相当没有它的内存消耗。

$ b

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


I'm working on fixing memory leaks in a large project, and so I've shrunk it down into one Main() method wherein a reference type object Obj1 containing a reference to another reference type object Obj2. Then, I create another object of type Obj1 which contains a reference to the same Obj2 object. Both of the objects are in their own using blocks, like so:

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

Somehow, when I take the 2 snapshots at the points commented above and compare them, .NET Memory Profiler indicates that even though the two objects obj1_a and obj1_b have been disposed, they haven't been GC'ed. When I examine the reference graphs, I see that the memory profiler says that both objects are referenced by my Main() method itself. I've gone through the whole code of the Main() method (it's not very complex, just creating, slightly modifying and then testing for garbage-collection) to see if there is a variable reference remaining to these two objects but there are none. How is it still possible that my Main() method could be holding these objects in memory? It's important that they get garbage collected (or at least are able to get GC'ed) because they contain references to many more reference and value types and the program becomes quite a memory drain without it.

解决方案

even though the two objects obj1_a and obj1_b have been disposed, they haven't been GC'ed

Your statement presupposes that there is a connection between an object being disposed and it being deallocated by the garbage collector. Make sure you fully understand the following statement: disposing an object has no effect whatsoever on whether it is eligible to be collected. From the GC's perspective, Dispose is just a method. You might as well say "even though I called ToString on an object, it still hasn't been GC'd". What does ToString have to do with the GC? Nothing. What does Dispose have to do with the GC? Nothing whatsoever.

Now, this slightly overstates the case. A finalizable object should implement IDisposable, and its Dispose should call SuppressFinalization. That has an effect on the garbage collector because finalizable objects always live at least one collection longer than they otherwise would because the finalization queue is a root. But here the effect is not due directly to Dispose; it is simply a convention that disposers suppress finalization. It is the suppression which has an effect on the GC behaviour.

How is it still possible that my Main() method could be holding these objects in memory?

An object is collected by the GC when the GC determines that there is no living root containing a direct or indirect reference to the object.

A local variable in an active method is a living root.

The runtime is permitted to, entirely at its discretion and for any reason whatsoever, to both (1) determine that a local is never read again and treat it as dead early, and (2) keep a local alive longer even when control has passed beyond the local variable declaration space of that variable.

Even though your obj1_a and obj1_b are out of scope by the time the GC runs, the runtime is entirely permitted to pretend that they were declared at the top scope of Main, and is permitted to keep them alive until Main completes, which is after the GC runs.

It's important that they get garbage collected (or at least are able to get GC'ed) because they contain references to many more reference and value types and the program becomes quite a memory drain without it.

If you require fine-grained control over lifetimes of objects then languages which have automatic memory deallocation do not meet your requirements.

这篇关于我的Main()方法如何保存对已经处理且不再使用的变量的引用?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆