这里是否需要 GC.KeepAlive,或者我可以依靠局部变量和参数来保持对象处于活动状态吗?
我有很多方法采用 WPF 的 WriteableBitmap
并使用不安全的代码直接从其 BackBuffer
读取。
每当我做这样的事情时,我是否应该使用 GC.KeepAlive 并不完全清楚:
int MyMethod(WriteableBitmap bmp)
{
return DoUnsafeWork(bmp.BackBuffer);
}
一方面,在 MyMethodbmp
的引用代码>的堆栈。另一方面,它似乎依赖于实现细节 - 这可以编译为尾部调用,例如,在输入 DoUnsafeWork
时不保留对 bmp
的引用。
同样,想象一下以下假设的代码:
int MyMethod()
{
WriteableBitmap bmp1 = getABitmap();
var ptr = bmp.BackBuffer;
WriteableBitmap bmp2 = getABitmap();
return DoUnsafeWork(ptr, bmp2);
}
理论上,对 bmp1 的引用保留在堆栈上,直到方法返回,但同样,它似乎使用了实现细节。当然,编译器可以自由地合并 bmp1
和 bmp2
因为它们永远不会同时存在,即使编译器从不这样做,JITter 仍然可以,并且可能会这样做(例如,将它们存储在同一个寄存器中,第一个,然后另一个)。
因此,一般来说:我应该依赖局部变量/参数作为对对象的有效引用,还是应该始终使用 GC.KeepAlive 来保证正确性?
这尤其令人费解,因为显然 FxCop 认为 GC.KeepAlive 是总是不好。
I have a bunch of methods that take the WPF's WriteableBitmap
and read from its BackBuffer
directly, using unsafe code.
It's not entirely clear whether I should use GC.KeepAlive
whenever I do something like this:
int MyMethod(WriteableBitmap bmp)
{
return DoUnsafeWork(bmp.BackBuffer);
}
On the one hand, there remains a reference to bmp
on MyMethod
's stack. On the other, it seems like relying on implementation detail - this could compile to a tail call, for example, keeping no reference to bmp
the moment DoUnsafeWork
is entered.
Similarly, imagine the following hypothetical code:
int MyMethod()
{
WriteableBitmap bmp1 = getABitmap();
var ptr = bmp.BackBuffer;
WriteableBitmap bmp2 = getABitmap();
return DoUnsafeWork(ptr, bmp2);
}
In theory, a reference to bmp1
remains on the stack until the method returns, but again, it seems like using an implementation detail. Surely the compiler is free to merge bmp1
and bmp2
because they're never live at the same time, and even if the compiler never does that surely the JITter still can, and probably does (e.g. by storing them both in the same register, first one, then the other).
So, in general: should I rely on locals/arguments being valid references to an object, or should I always use GC.KeepAlive
to guarantee correctness?
This is especially puzzling since, apparently, FxCop thinks GC.KeepAlive is always bad.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
不,你的分析是正确的;抖动完全有权告诉垃圾收集器本地内容在不再被托管代码使用时就已死亡。
是的。这就是它的用途。
No. Your analysis is correct; the jitter is entirely within its rights to tell the garbage collector that the contents of the local are dead the moment they are no longer in use by managed code.
Yes. That's what it's for.
如果您在获取后台缓冲区之前调用了 WriteableBitmap.Lock,则应该固定 WriteableBitmap 并且底层内存不会被移动。至少这是我对 WriteableBitmapAPI 的解释。
我广泛使用了 WriteableBitmap,特别是 codeplex 上的开源 WriteableBitmapEx 库(披露,我曾为该库贡献过一次,但它不是我的项目)。这里使用Lock/Access Backbuffer(重复)/unlock/Invalidate的模式来绘制。尽管后缓冲区 IntPtr 存储在结构中并在应用程序中传递,但我从未遇到过这种模式的问题。
此致,
If you have called WriteableBitmap.Lock before getting the back buffer then the WriteableBitmap should be pinned and underlying memory will not be moved. At least that's my interpretation of the WriteableBitmapAPI.
I have used WriteableBitmap extensively, in particular the open source WriteableBitmapEx library on codeplex (disclosure, I have contributed once to this library but its not my project). This uses the pattern of Lock / Access Backbuffer (repeatedly) / unlock / Invalidate to draw. I've never had a problem with this pattern even though the backbuffer IntPtr is stored in a struct and passed around the application.
Best regards,