Is GC.KeepAlive required here, or can I rely on lo

2019-06-15 13:55发布

问题:

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.

回答1:

Should I rely on locals/arguments being valid references to an object?

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.

should I always use GC.KeepAlive to guarantee correctness?

Yes. That's what it's for.



回答2:

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,