本文介绍了在终结器中使用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#中的内存泄漏的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!