Linked Questions

Popular Questions

C# Finalizer not freeing unmanaged memory

Asked by At

I have a MappedMemory class that allocates a chunk of memory via Marshal.AllocHGlobal(). The class implements IDisposable, and I have it set up to auto-dispose the allocated memory when the class is finalized. However, it does not appear to be working as intended.

class MappedMemory : IDisposable
{
    private bool disposed_ = false;
    private IntPtr memoryPtr_;

    public MappedMemory( int capacity )
    {
      memoryPtr_ = Marshal.AllocHGlobal( capacity );
    }

    ~MappedMemory()
    {
      Dispose( false );
    }

    public void Dispose()
    {
      Dispose( true );
      GC.SuppressFinalize( this );
    }

    protected virtual void Dispose( bool disposing )
    {
      if ( !disposed_ )
      {
        if ( disposing )
        {
          // Clear managed resources
        }

        Marshal.FreeHGlobal( memoryPtr_ );
      }
      disposed_ = true;
    }
}

I have written two tests to ensure that the memory is being freed properly:

public MappedMemory_finalizer_frees_memory()
{
  for( var i = 0; i < 1e8; i++ )
  {
    var memory = new MappedMemory( 128 );
  }
}

public MappedMemory_dispose_frees_memory()
{
  for( var i = 0; i < 1e8; i++ )
  {
    var memory = new MappedMemory( 128 );
    memory.Dispose();
  }
}

When the tests are run, the test that manually calls Dispose() works as it should, and memory stays at a constant utilization.

The test for the finalizer, however, does not appear to be freeing the allocated memory, and it leaks out of control until it runs out of memory. I have set a breakpoint and the call to Marshal.FreeHGlobal( memoryPtr_ ) is hit.

Manually adding GC.Collect() to the test fixes the problem, so ultimately it appears that the memory is deallocated, but not garbage collected?

I am super confused as to what is happening here. Can someone explain why the finalizer does not free the memory, and how I can ensure that it does in production?

Related Questions