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);
    }
}
Другие вопросы по тегам