Финализатор C # не освобождает неуправляемую память - PullRequest
0 голосов
/ 11 февраля 2019

У меня есть класс MappedMemory, который выделяет кусок памяти через Marshal.AllocHGlobal().Класс реализует IDisposable, и я настроил его на автоматическое удаление выделенной памяти, когда класс будет завершен.Однако он не работает должным образом.

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() к тесту устраняет проблему, поэтому в конечном итоге создается впечатление, что память освобождена, а не собрана сборщиком мусора?

Я очень озадачен тем, что здесь происходит.Может кто-нибудь объяснить, почему финализатор не освобождает память, и как я могу гарантировать, что он делает это в производстве?

1 Ответ

0 голосов
/ 11 февраля 2019

Из документации MSDN здесь: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/destructors

Программист не может контролировать, когда вызывается финализатор, поскольку это определяется сборщиком мусора.Сборщик мусора проверяет объекты, которые больше не используются приложением.Если он считает объект пригодным для завершения, он вызывает финализатор (если есть) и освобождает память, используемую для хранения объекта.

Поскольку вы говорите, что принудительное удаление мусора освобождает память, я подозреваю, чтоПроблема, с которой вы сталкиваетесь, заключается в том, что в системах памяти недостаточно нагрузки для автоматического запуска сборки мусора.Сборка мусора является относительно дорогим процессом, поэтому он не запускается, если для этого нет причин.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...