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

本文关键字:对象 本机 gen2 CLI | 更新日期: 2023-09-27 18:13:28

我正在研究这个高频生产系统。有一个c#/CLI层调用一个c++库。我们观察到的是,托管对象进入了垃圾收集器的第2代,并被"卡住"了。最终,随着内存耗尽,c#应用程序陷入停顿。这些托管对象是本地对象,应该具有非常短的生存期。而且它们只被引用一次。c#应用程序必须对所有拥有本机资源的对象调用. dispose(),以确保所有内容都被强制删除。我们有相当多的对象,所以这不是理想的,从API的角度来看是混乱的。命令行如下所示:

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;
    }
}

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

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

问题是非托管对象不计入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);
    }
}
相关文章: