【问题标题】:CLI Native objects getting stuck in gen2 and not garbage collectedCLI Native 对象卡在 gen2 中并且没有被垃圾回收
【发布时间】:2017-02-27 21:46:22
【问题描述】:

我正在研究这个高频制作系统。有一个调用 C++ 库的 C#/CLI 层。我们观察到的是托管对象正在进入垃圾收集器的第 2 代并被“卡住”。最终,由于 RAM 耗尽,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;
    }
}

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

【问题讨论】:

  • 它被称为C++/CLI 而不是C#/CLI。确保使用正确的术语,否则在搜索问题的解决方案时将很难找到相关信息。
  • 没有多少实际场景可以将临时对象提升到第 2 代。水晶球说终结器线程已死锁。使用非托管调试器查看一下。
  • 回想起来,这些东西进入了第 1 代,我们所做的分析是不正确的。 Scotts 的推理是有道理的。

标签: c# garbage-collection c++-cli dispose finalize


【解决方案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);
    }
}

【讨论】:

  • 还有其他选择吗?因为找到我们的一些原生物体的大小非常棘手,而且不是一门精确的科学。
猜你喜欢
  • 1970-01-01
  • 2011-10-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-05-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多