gpt4 book ai didi

c# - 使用带有终结器的 C++/CLI 定义类时 C# 中的内存泄漏

转载 作者:行者123 更新时间:2023-11-30 12:11:24 26 4
gpt4 key购买 nike

当我在 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 中实现终结器时都会发生这种内存泄漏(或垃圾收集的不良工作)。

为什么会发生内存泄漏?我怎样才能避免它并仍然能够将终结器用于其他(更复杂的)用途?


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

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

最佳答案

当分配速度快于垃圾收集速度时,您将遇到 OOM。如果你进行大量分配,CLR 将插入一个 Sleep(xx) 来限制分配,但这在你的极端情况下是不够的。

当你实现一个终结器时,你的对象被添加到终结队列中,当它被终结时,它被从队列中移除。这确实会带来额外的开销,并且您会使对象的生命周期比必要的更长。即使您的对象可以在便宜的 Gen 0 GC 期间被释放,它仍然会被终结队列引用。当发生完整 GC 时,CLR 会触发终结线程开始清理。这无济于事,因为您的分配速度确实快于最终确定速度(写入标准输出非常慢)并且您的最终确定队列将变得越来越大,导致最终确定时间越来越慢。

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

您需要记住,终结是一种固有的异步操作,在特定时间点无法保证执行。 CLR 永远不会等到清除所有挂起的终结器之后才允许进行额外的分配。如果您在 10 个线程上分配,仍然会有一个终结器线程在您之后进行清理。如果您想依赖确定性终结,则需要通过调用 GC.WaitForPendingFinalizers() 等待但这会让你的表现停滞不前。

因此,您的 OOM 是意料之中的。

关于c# - 使用带有终结器的 C++/CLI 定义类时 C# 中的内存泄漏,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15521233/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com