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