繁体   English   中英

.NET GC删除正在使用的对象

[英].NET GC deleting object in use

我遇到了一个问题,在该问题中似乎GC线程正在唤醒并在使用对象时将其删除。

当processfoo运行时,在返回之前,它会在单独的线程中触发fooCopy析构函数。 有人看到过这样的问题吗?如果是,您如何解决呢? 当然,这不可能真的发生,我必须做错了什么。 谁能给我一些调试垃圾收集的提示/策略?

try
{
    CFoo fooCopy = new CFoo(someFoo);
    someBar.ProcessFoo(fooCopy);
}

CFoo具有IntPtr成员变量。 ProcessFoo将该成员变量从C ++ DLL传递到导入的函数,这可能需要花费几秒钟来运行。

在我的C ++ DLL中,我记录了何时创建IntPtr以及何时删除了IntPtr,并且可以看到在ProcessFoo运行时删除IntPtr的单独线程。

当然,这不可能真的发生,我必须做错了什么。

是的,这绝对是有可能发生的(这就是为什么编写终结器很难,并且您应该尽可能避免使用终结器,并且在强制编写终结器时要非常小心)。 只要运行时证明没有代码会再次尝试访问该对象,就可以对其进行GC处理。 如果你调用一个实例方法(和任何时间调用之后从未访问对象实例),那么物体的最近使用后立即可享有集合this从实例方法。

在范围内(例如,方法的this变量)但在该范围内不再使用的对象不会被GC视为根对象

至于如何解决它,如果您拥有一个即使不再在托管代码中都无法访问的变量,都希望将其视为“有效”的变量,请使用GC.KeepAlive 在这种情况下,将GC.KeepAlive(this)添加到ProcessFoo的末尾将确保所讨论的对象保持活动状态直到方法结束(或者,如果不是该方法的职责,请调用方调用GC.KeepAlive(someBar)就在ProcessFoo之后)。

有关主题的更多信息以及终结器的一些甚至更不寻常的属性,请参见此博客文章

当您与C ++互操作时,这是很正常的,GC没有希望发现IntPtr在其他任何地方都在使用。 这不是GC知道的参考类型,也不能探测本机代码的堆栈框架。 抖动fooCopy对象引用标记为fooCopy使用基础CALL,而不超出此范围。 换句话说,它可以执行本机代码时进行收集。 如果另一个线程触发了GC,则为sayon​​ora。

您可以在这篇文章中找到有关局部变量生存期的详细信息。

有几种可能的解决方法,尽管无法从问题中猜出正确的方法。 除了SafeHandle类之外,还非常擅长确保完成终结处理,可以在[DllImport]声明中使用HandleRef代替IntPtr。 或将GC.KeepAlive()附加到此代码,以强制抖动延长fooCopy的寿命。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM