简体   繁体   English

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

[英].NET GC deleting object in use

I'm running into a problem where it would appear the GC thread is waking up and deleting an object while it's in use. 我遇到了一个问题,在该问题中似乎GC线程正在唤醒并在使用对象时将其删除。

While processfoo is running, and before it returns, it would appear fooCopy destructor fires in a separate thread. 当processfoo运行时,在返回之前,它会在单独的线程中触发fooCopy析构函数。 Has anyone seen a problem like this and if so how do you work around it? 有人看到过这样的问题吗?如果是,您如何解决呢? Surely, this can't be really happening and I must be doing something wrong. 当然,这不可能真的发生,我必须做错了什么。 Can anyone give me some tips/strategies to debug the garbage collection? 谁能给我一些调试垃圾收集的提示/策略?

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

CFoo has an IntPtr member variable. CFoo具有IntPtr成员变量。 ProcessFoo passes that member variable to an imported function from a C++ DLL that might take a few seconds to run. ProcessFoo将该成员变量从C ++ DLL传递到导入的函数,这可能需要花费几秒钟来运行。

In my C++ DLL I log when the IntPtr is created and when it is deleted and I can see a separate thread deleting the IntPtr while ProcessFoo is running. 在我的C ++ DLL中,我记录了何时创建IntPtr以及何时删除了IntPtr,并且可以看到在ProcessFoo运行时删除IntPtr的单独线程。

Surely, this can't be really happening and I must be doing something wrong. 当然,这不可能真的发生,我必须做错了什么。

Nope, it can absolutely be happening (this is why writing finalizers is hard, and you should avoid them where you can, and be very careful when forced to write them). 是的,这绝对是有可能发生的(这就是为什么编写终结器很难,并且您应该尽可能避免使用终结器,并且在强制编写终结器时要非常小心)。 An object can be GC-ed as soon as the runtime can prove that no code will ever try to access it again. 只要运行时证明没有代码会再次尝试访问该对象,就可以对其进行GC处理。 If you call an instance method (and never access the object instance any time after that invocation) then the object is eligible for collection immediately after the last usage of this from that instance method. 如果你调用一个实例方法(和任何时间调用之后从未访问对象实例),那么物体的最近使用后立即可享有集合this从实例方法。

Objects that are in scope (say, for example, the this variable of a method) but that are never used again within that scope are not considered rooted by the GC . 在范围内(例如,方法的this变量)但在该范围内不再使用的对象不会被GC视为根对象

As for how you work around it, if you have a variable that you want to be considered "alive" even though it's never accessed in managed code again, use GC.KeepAlive . 至于如何解决它,如果您拥有一个即使不再在托管代码中都无法访问的变量,都希望将其视为“有效”的变量,请使用GC.KeepAlive In this case, adding GC.KeepAlive(this) to the end of ProcessFoo will ensure that the object in question stays alive until the end of the method (or if it's not that method's responsibility, have the caller call GC.KeepAlive(someBar) right after ProcessFoo ). 在这种情况下,将GC.KeepAlive(this)添加到ProcessFoo的末尾将确保所讨论的对象保持活动状态直到方法结束(或者,如果不是该方法的职责,请调用方调用GC.KeepAlive(someBar)就在ProcessFoo之后)。

See this blog post for more information on this topic, and a few related and even more unusual properties of finalizers. 有关主题的更多信息以及终结器的一些甚至更不寻常的属性,请参见此博客文章

This is pretty normal when you interop with C++, the GC has no hope of discovering that the IntPtr is in use anywhere else. 当您与C ++互操作时,这是很正常的,GC没有希望发现IntPtr在其他任何地方都在使用。 It is not a reference type that the GC has awareness of, nor can it probe the stack frames of native code. 这不是GC知道的参考类型,也不能探测本机代码的堆栈框架。 The jitter marks the fooCopy object reference in use up to the underlying CALL, not beyond that. 抖动fooCopy对象引用标记为fooCopy使用基础CALL,而不超出此范围。 In other words, it is eligible for collection while the native code is executing. 换句话说,它可以执行本机代码时进行收集。 If another thread triggers a GC then it is sayonora. 如果另一个线程触发了GC,则为sayon​​ora。

You'll find details about the lifetime of local variables in this post . 您可以在这篇文章中找到有关局部变量生存期的详细信息。

There are several possible workarounds for this, albeit that the correct one can't be guessed from the question. 有几种可能的解决方法,尽管无法从问题中猜出正确的方法。 Beyond the SafeHandle classes, very good at ensuring the finalization is taken care of as well, you could use HandleRef instead of IntPtr in the [DllImport] declaration. 除了SafeHandle类之外,还非常擅长确保完成终结处理,可以在[DllImport]声明中使用HandleRef代替IntPtr。 Or append GC.KeepAlive() to this code to force the jitter to extend the lifetime of fooCopy . 或将GC.KeepAlive()附加到此代码,以强制抖动延长fooCopy的寿命。

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

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