在终结器中使用C++/CLI定义的类时C#中的内存泄漏 [英] Memory leaks in C# while using C++/CLI defined class with finalizer

查看:63
本文介绍了在终结器中使用C++/CLI定义的类时C#中的内存泄漏的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

当我在C++/CLI DLL中实现类时:

public ref class DummyClass
{
protected:
    !DummyClass() 
    {
        // some dummy code:
        std::cout << "hello" << std::endl;
    }
}

当我将DLL加载到C#项目并仅通过重复创建对象来使用该类时:

static void Main()
{
    while (true)
    {
        var obj = new DummyClass();
    }
}

然后,在运行该程序时,内存将慢慢消化为OutOfMemoryException。

似乎每次我在C++/CLI中实现终结器时都会发生这种内存泄漏(或垃圾回收的糟糕工作)。

为什么会发生这种内存泄漏?我如何才能避免它,同时仍能将终结器用于其他(更复杂的)用途?


update:原因肯定不是写入控制台/stdout或终结器中的其他非标准代码,以下类具有相同的内存泄漏行为:

public ref class DummyClass
{
private:
    double * ptr;
public:
    DummyClass()
    {
         ptr = new double[5];
    }
protected:
    !DummyClass() 
    {
         delete [] ptr;
    }
}

推荐答案

当分配速度超过垃圾收集速度时,您将遇到面向对象对象模型。如果您进行大量分配,CLR将插入一个睡眠(Xx)来限制分配,但在极端情况下这是不够的。

当您实现终结器时,您的对象将被添加到终结化队列中,当它被终结化时,它将从队列中删除。这确实会增加额外的开销,并且会使对象的寿命比必要的更长。即使您的对象可以在廉价的Gen 0GC期间被释放,它仍然被终结队列引用。当发生完全GC时,CLR确实会触发finalizaion线程开始清理。这没有任何帮助,因为您的分配速度确实快于您可以完成的速度(写入标准输出的速度非常慢),并且您的完成队列将变得越来越大,从而导致完成时间越来越慢。

我没有测量过它,但我认为即使是空的终结器也会导致此问题,因为增加的对象生存期和两个终结器队列处理(终结器队列和f-Reacable队列)确实会带来足够的开销,从而使终结器比分配慢。

您需要记住,终结是固有的异步操作,在特定时间点没有执行保证。在允许额外分配之前,CLR绝不会等待清除所有挂起的终结器。如果您分配给10个线程,那么在您之后仍会有一个终结器线程在清理。如果您希望依赖确定性终结,则需要通过调用EgWaitForPendingFinalizers()进行等待。 但这会让你的表演停滞不前。

因此,您的OOM是预期的。

这篇关于在终结器中使用C++/CLI定义的类时C#中的内存泄漏的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆