I've read about this issue on MSDN and on CLR via c#.
Imagine we have a 2Mb unmanaged HBITMAP allocated and a 8 bytes managed bitmap pointing to it. What's the point of telling the GC about it with AddMemoryPressure if it is never going to be able to make anything about the object, as it is allocated as unmanaged resource, thus, not susceptible to garbage collections?
The point of AddMemoryPressure is to tell the garbage collector that there's a large amount of memory allocated with that object. If it's unmanaged, the garbage collector doesn't know about it; only the managed portion. Since the managed portion is relatively small, the GC may let it pass for garbage collection several times, essentially wasting memory that might need to be freed.
Yes, you still have to manually allocate and deallocate the unmanaged memory. You can't get away from that. You just use AddMemoryPressure to ensure that the GC knows it's there.
Edit:
I think I see your issue.
Yes, if you can guarantee that you always call
Dispose
, then yes, you don't need to bother with AddMemoryPressure and RemoveMemoryPressure. There is no equivalence, since the reference still exists and the type would never be collected.That said, you still want to use AddMemoryPressure and RemoveMemoryPressure, for completeness sake. What if, for example, the user of your class forgot to call Dispose? In that case, assuming you implemented the Disposal pattern properly, you'll end up reclaiming your unmanaged bytes at finalization, i.e. when the managed object is collected. In that case, you want the memory pressure to still be active, so that the object is more likely to be reclaimed.
Put it this way, still assuming the 8 byte managed objects each referring to a 2 MB unmanaged image. The GC might wait a long time before collecting hundreds or thousands of the little managed objects, because they are so small. That would mean that also hundreds or thousands of linked 2 MB unmanaged chunks will stay alive, awaiting removal. That could become a huge problem. By adding 2 MB of memory pressure in the constructor you will make GC think that the managed object is not 8 bytes big but rather 8 bytes + 2 MB. That will trigger collection way earlier.
Don't forget the Remove call.
Of course if you dispose yourself then you won't need all that.
It is provided so that the GC knows the true cost of the object during collection. If the object is actually bigger than the managed size reflects, it may be a candidate for quick(er) collection.
Brad Abrams entry about it is pretty clear:
These methods allow the runtime to have some sense of how much unmanaged memory is being allocated by the process. Without calling these functions, it may not be able to see the true amount of unmanaged memory in use within the process.
However I disagree with the other answers here regarding an association between the memory being referred to and a particular GC object.
Consider:
There is no way for the GC to assign the
size
to a specific object. This code could even exist in a static method.Therefore I assert that the statement we need to “teach” the GC about the true cost of this instance so that it will accurately know when to kick of a collection to free up more memory in the process is incorrect and misleading.
Instead this method might cause the GC to collect earlier than it would otherwise, in an effort to avoid running out of memory.