CLI Нативные объекты застряли в gen2, а не сборщик мусора
Я работаю над этой высокочастотной производственной системой. Существует уровень C# / CLI, который вызывает библиотеку C++. Мы наблюдаем, что управляемые объекты попадают во второе поколение сборщика мусора и застревают. В конечном счете приложения C# останавливаются, когда заканчивается ОЗУ. Эти управляемые объекты являются локальными объектами и должны иметь очень короткое время жизни. Также на них ссылаются только один раз. Приложения C# должны вызывать.Dispose() для всех своих объектов, которые содержат собственные ресурсы, чтобы гарантировать принудительное удаление всего. У нас есть довольно много объектов, так что это не идеально, и с точки зрения API это грязно. CLI выглядит так:
Field::~Field()
{
if(m_pField != NULL)
{
delete m_pField;
m_pField = NULL;
}
System::GC::SuppressFinalize(this);
}
Field::!Field()
{
if(m_pField != NULL)
{
delete m_pField;
}
}
Кто-нибудь может подумать, почему эти недолговечные объекты никогда не собираются и не освобождают память?
1 ответ
Проблема заключается в том, что неуправляемые объекты не учитываются в значении "давления памяти", которое GC использует, чтобы решить, когда выполнять сборку мусора.
Одна вещь, которую вы можете сделать, это использовать GC.AddMemoryPressure(
сообщить GC, что с вашей управляемой оболочкой связан большой неуправляемый объект.
Field::Field()
{
//... Other stuff
if(m_pField != NULL)
{
m_lSizeOfField = GetSizeOfField(m_pField);
System::GC::AddMemoryPressure(m_lSizeOfField);
}
}
Field::~Field()
{
//If you had managed objects you would call "delete" here on them.
//delete m_managedData;
//In C++/CLI if you have unmanged resources just have the dispose method
// call the finalizer. It is cleaner and easier to maintain.
// You can't do this in C#
this->!Field();
//No need to add this next line, C++/CLI does it for you.
//System::GC::SuppressFinalize(this);
}
Field::!Field()
{
if(m_pField != NULL)
{
delete m_pField;
m_pField = NULL;
System::GC::RemoveMemoryPressure(m_lSizeOfField);
}
}