How can I dispose of an object (say a Bitmap) when

2019-05-04 19:10发布

问题:

I have a class A providing Bitmaps to other classes B, C, etc.

Now class A holds its bitmaps in a ring queue so after a while it will lose reference to the bitmap.

While it's still in the queue, the same Bitmap can be checked out by several classes so that, say, B and C can both hold a reference to this same Bitmap. But it can also happen that only one of them checked out the Bitmap or even none of them.

I would like to dispose of the bitmap when it's not being needed any more by either A, B or C.

I suppose I have to make B and C responsible for somehow signaling when they're finished using it but I'm not sure about the overall logic.

Should it be a call to something like DisposeIfNowOrphan() that would be called, in this example, three times :

1 - when the Bitmap gets kicked out of the queue in class A

2 - when B is finished with it

3 - when C is finished with it

If that's the best strategy, how can I evaluate the orphan state ?

Any advice would be most welcome.

回答1:

Have class A provide a wrapper class instead of a bitmap directly. The wrapper class should implement IDisposable itself and can be used to maintain a counter. Each consumer can get their own wrapper which references the same Bitmap. Class A keeps trap of all bitmaps and all wrappers. Use a WeakReference in Class A to keep track of the wrappers so if a consumer doesn't call dispose, it will get GC'd and the provider can know it's no longer referenced.



回答2:

Bitmap inherits from Image, which implements IDisposable, so when you're done using an instance, you should call Dispose() on it. This will clean up the unmanaged resource in Image.

However, Image also implements a finalizer, so if for some reason you cannot call Dispose(), the resource will be reclaimed during finalization of the instance, which will happen at some point after the instance is no longer referenced.



回答3:

If memory usage isn't such a big issue and correctness and clarity are more important ...

Give each recipient their own copy of the bitmap and have a using() statement around the code that uses it.

Your management code is now very easy, and your consumption code is also very easy. It's also very easy to see (prove?) that the whole thing will work even when your consumers might have exceptions and other code paths making it hard (or impossible) to be sure that reference counters were decremented (or such like).

Using the time you have saved developing your own GC solution for shared bitmaps, take the money and buy another stick of RAM for your server.



回答4:

If, on the other hand, peak memory consumption is the key issue ... but you still want a 'safe' approach where you can be sure that bitmap lifetimes are being managed properly regardless as to the consumer code you could invert the problem and say that the producer is solely responsible for all operations on the images in its own thread (or threads). So instead of handing out images to other classes to work on you ask the other classes to hand in Actions to carry out on images. You maintain a queue of pending actions and can look ahead in the queue to decide which images to toss from the buffer based on having no future work to do on them.

Since these images will likely be on the large object heap it's important to manage their lifetimes appropriately to minimize fragmentation of the large object heap.