Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

GC.AddMemoryPressure

I am writing an application in C# that makes use of a 3rd party COM DLL, this dll creates a lot of resources (like bitmaps, video, data structures) in unmanaged memory. While digging around I came across the following call for the Garbage Collector:

GC.AddMemoryPressure(long long bytesAllocated)

It is documented in MSDN here:

http://msdn.microsoft.com/en-us/library/system.gc.addmemorypressure.aspx

This sounds like something I should be calling since this external dll is createing a lot of resources the CLR is unaware of.

I guess I have two questions...

  1. How do I know how much memory pressure to add when the dll is 3rd party and it's not possible for me to know exactly how much memory this dll is allocating.
  2. How important is it to do this?
like image 518
Steve Sheldon Avatar asked Apr 11 '10 17:04

Steve Sheldon


2 Answers

In any mixed native/managed process, there is a mixture of native/managed memory usage. If there is no GC-controlled relationship between the two, then there would be no need for this API. For example, if there are certain deterministic state changes in the managed code that cause native memory to be allocated and deallocated, then nothing the GC can do will ever force native memory to be released.

However, very often there is native memory held by managed objects that have finalizers. So the GC can reduce the size of the native heap, simply by triggering a collection and getting those finalizers to run.

Therefore if you have a lot of that going on, it could well be necessary to call this API (just like the documentation says).

As for how much you should tell it, that's probably not something you can cook up an answer for by pure analysis, especially with a 3rd party library. You need to run Performance Monitor, run a test that allocates a lot of the 3rd party objects, and look at the Native Bytes and CLR memory counters to see how they relate.

As you're using a COM object, you could in fact deterministically force instances to clean up when you know you no longer need them, by using Marshal.ReleaseComObject. Note that you need to use a goofy loop to make it get rid of the object:

while (Marshal.ReleaseComObject(obj) != 0) 
{
}
like image 194
Daniel Earwicker Avatar answered Nov 10 '22 21:11

Daniel Earwicker


Let's say I have an object like this:

public class SomeImageType : IDisposable
{
    public int Width { get; private set; }
    public int Height { get; private set; }
    public PixelFormat PixelFormat { get; private set; }
    IntPtr ImageData { get; private set; }
    // implementation of constructor and IDisposable not shown
}

How much memory does this take? 20 bytes + object overhead? When it comes time for collection, if this object has no references it makes no difference at all. But does it take that 20 bytes? Hell no - it's an image. So take that 20 and multiply it by the width, the height and the number of bytes per pixel and you have something that takes up (possibly) megabytes. By telling the GC to add memory pressure, you are saying that there is an iceberg in there chewing up resources. When you dispose the object, you will, of course, free that memory and tell the GC to release that pressure. These two calls let you hint to the GC that there are strange things afoot at the Circle K, and maybe it would like to schedule collection differently.

like image 45
plinth Avatar answered Nov 10 '22 20:11

plinth