views:

532

answers:

2

I've read about it on msdn and on CLR via c#.

My main question about it is the following: let's 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?

+5  A: 

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:

Consider a class that has a very small managed instance size but holds a pointer to a very large chunk of unmanaged memory. Even after no one is referencing the managed instance it could stay alive for a while because the GC sees only the managed instance size it does not think it is “worth it” to free the instance. So 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.

Steven Lyons
Actually, now that I re-read your post I my question stands still. After I use my bitmap, I will call dispose on it, so it actually will only take 8 bytes of memory. If in the other hand, I did not call dispose, well, then it really ocuppies 2mb of memory. There's the 3rd case of where there isn't a dispose method, so the GC can do nothing for it. So, the GC knowing the real size of the type will only help in situation 2. Or am I missing something?
devoured elysium
In case 1, you will want to call GC.AddMemoryPressure on bitmap allocation and then GC.RemoveMemoryPressure when you manually release the bitmap. That will ensure that the object correctly reflects its size to the GC. However, if there is a way to be sure that the GC is never run while your object is eligible for collection and the bitmap is allocated, these methods might not matter.
Steven Lyons
Well, in case one, I could do it, but it'd make no big difference, as the GC wouldn't be able to do a thing about my type, if I understand this correctly: 1) I'd declare my variable, 8 managed bytes, 2mb unmanaged bytes. I'd then use it, call dispose, so unmanaged memory is freed. Right now it will only ocuppy 8 bytes. Now, to my eyes, having called in the beggining AddMemoryPressure and RemoveMemoryPressure at the end wouldn't have made anything different. What am I getting wrong? Sorry for being so anoying about this.
devoured elysium
@Jorge Branco: I think I see your problem. I've edited my original answer to respond to your last comment.
Randolpho
I think you understand it fine. The one thing missing from your example is that the GC may initiate a collection because of the memory pressure from your object (though it won't collect the object since it is in use). Other than that, if your objects are always disposed correctly I don't think it will provide you much for those objects. If you don't have control over the usage of your objects, using these APIs would probably be of more use.
Steven Lyons
+2  A: 

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:

Well, in case one, I could do it, but it'd make no big difference, as the GC wouldn't be able to do a thing about my type, if I understand this correctly: 1) I'd declare my variable, 8 managed bytes, 2mb unmanaged bytes. I'd then use it, call dispose, so unmanaged memory is freed. Right now it will only ocuppy 8 bytes. Now, to my eyes, having called in the beggining AddMemoryPressure and RemoveMemoryPressure at the end wouldn't have made anything different. What am I getting wrong? Sorry for being so anoying about this. -- Jorge Branco

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.

Randolpho
Well, that didn't answer the question, lol.
devoured elysium
I said almost exactly what Steven Lyons said, only in a different way. How did it not answer the question?
Randolpho
Well, actually I re-read it and edited my post.
devoured elysium
Ok. Thanks, now I think you got my point, and I agree with your about using it for completeness.
devoured elysium