CLI 本机对象卡在 gen2 而不是垃圾收集

CLI Native objects getting stuck in gen2 and not garbage collected

我正在研究这个高频生产系统。有一个调用 C++ 库的 C# / CLI 层。我们观察到的是托管对象进入垃圾收集器的第 2 代并获得 'stuck'。最终,C# 应用程序会因为 RAM 耗尽而停止运行。这些托管对象是本地对象,应该有很短的生命周期。它们也只被引用一次。 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;
    }
}

谁能想到为什么这些短暂的对象似乎永远不会被收集并释放内存?

问题是非托管对象不计入 GC 用来决定何时执行垃圾回收的 "memory pressure" 值。

您可以做的一件事是使用 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);
    }
}