C# 终结器不释放非托管内存

C# Finalizer not freeing unmanaged memory

我有一个 MappedMemory class,它通过 Marshal.AllocHGlobal() 分配了一块内存。 class 实现了 IDisposable,我将其设置为在 class 完成时自动处理分配的内存。但是,它似乎没有按预期工作。

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;
    }
}

我写了两个测试来确保内存被正确释放:

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();
  }
}

当测试为运行时,手动调用Dispose()的测试正常运行,内存保持恒定利用率。

然而,终结器的测试似乎并没有释放分配的内存,它会失控地泄漏,直到 运行 内存不足。我已经设置了一个断点并且调用了 Marshal.FreeHGlobal( memoryPtr_ )

手动添加 GC.Collect() 测试解决了这个问题,所以最终看起来内存被释放了,但没有被垃圾回收?

我对这里发生的事情感到非常困惑。有人可以解释为什么终结器不释放内存,我如何确保它在生产中释放内存?

来自此处的 MSDN 文档:https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/destructors

The programmer has no control over when the finalizer is called because this is determined by the garbage collector. The garbage collector checks for objects that are no longer being used by the application. If it considers an object eligible for finalization, it calls the finalizer (if any) and reclaims the memory used to store the object.

正如您所说,强制垃圾回收会释放内存,我怀疑您看到的问题是内存系统没有足够的压力导致垃圾回收自动 运行。垃圾收集是一个相对昂贵的过程,所以它不是 运行 除非有理由这样做。