Performance Guideline: Use AddMemoryPressure while consuming Unmanaged Objects through COM Interop

Here's the next .NET Framework 2.0 performance guideline for review from Prashant Bansode, Bhavin Raichura, Girisha Gadikere and Claudio Caldato. 

Use AddMemoryPressure while consuming Unmanaged Objects through COM Interop

Applies to

  • .NET 2.0

What to Do
Use .NET 2.0 CLR API AddMemoryPressure and RemoveMemoryPressure while consuming the Unmanaged Objects from Managed Code through COM Interop.

Why
The garbage collector cannot track the Memory allocated by Unmanaged Code, it only tracks the Memory allocated by Managed Code.

If there is a large amount of memory allocation (such as images or video data) in the unmanaged code, the GC will be able to see only the reference of unmanaged objects, but not the size of the memory occupied by the unmanaged object references.

Since GC may be unaware of the large memory allocation within unmanaged code, the GC will not know that a collection should be executed, as it does not realize any "memory pressure" to cause a collection.

The AddMemoryPressure method can be used to inform GC about how much unmanaged memory a managed object will be referencing, when it consumes the Unmanaged Objects from Managed Code. The pro-active indication to GC improves the GC heuristics and collection algorithm, which improves memory management and performance.

When
If the Unmanaged Objects invoked from Managed Code allocates a large amount of unmanaged memory at runtime, the GC should be informed about the total memory consumed by the managed and unmanaged code, by invoking AddMemoryPressure method, to improve memory management of GC.

How
Applying memory pressure is the technique using which the GC can be informed about the memory allocation that might be performed by the unmanaged code within a managed code wrapper.

The AddMemoryPressure should be used to inform GC about probable memory allocation by the unmanaged code:

 Bitmap (string path )
 {
    _size = new FileInfo(path).Length;
    GC.AddMemoryPressure(_size);
    // other work
 }

The RemoveMemoryPressure should be used to inform GC to remove memory pressure while destroying the wrapper managed object which was consuming the unmanaged objects:

 ~Bitmap()
 {
    GC.RemoveMemoryPressure(_size);
    // other clean up code
 }

Note For every AddMemeoryPressure call, there must be a matching RemoveMemoryPressure call which will remove exactly the same amount of memory pressure as added earlier. Failing to do so can adversely affect the performance of the system in applications that run for long periods of time.

Problem Example
A .NET 2.0 application uses unmanaged objects that allocate large amount of memory at runtime to load images and video data.

It actually uses unmanaged memory and occupies large amount of system memory. Since the garbage collector cannot track the memory allocated by unmanaged code, the application might run low on memory without triggering garbage collection, degrading the performance of the application.

 class Bitmap
 {
   private long _size;
   Bitmap (string path )
   {
      _size = new FileInfo(path).Length;
       // other work
   }
   ~Bitmap()
   {
      // other work
   }
 }

Solution Example
A .NET 2.0 application uses unmanaged objects that allocate large amount of memory at runtime to load images and video data.

Use of AddMemoryPressure and RemoveMemoryPressure informs about the memory allocation and deallocation that might be performed by the unmanaged code within a managed code wrapper. The GC will know to perform a collection when there is a memory pressure and will work efficiently.

 class Bitmap
 {
   private long _size;
   Bitmap (string path )
   {
      _size = new FileInfo(path).Length;
      GC.AddMemoryPressure(_size);
      // other work
   }
   ~Bitmap()
   {
      GC.RemoveMemoryPressure(_size);
      // other work
   }
 }

Additional Resources