抑制GC内存优化

时间:2012-12-30 10:07:52

标签: c# garbage-collection defragmentation

我正在编写一个程序,在多个线程中调用多个基于C的函数(p / Invoke)。

程序有时会因访问冲突错误而崩溃。我的第一个想法是GC优化了内存并将C函数正在处理的内存块移动到另一个位置。

我想要做的是让GC工作但禁用它移动的部分(defrags)内存。

有办法做到这一点吗?

3 个答案:

答案 0 :(得分:5)

正如其他答案所说,首先要做的是确保正确固定对象。假设你已经做到了,还有什么可能出错?

class C
{
    public int handle;
    ...
    ~C() { InteropLibrary.DestroyHandle(handle); }
}

void M()
{
    C c = GetSomeObjectUsefulInUnmanagedCode();
    D d = InteropLibrary.UnmanagedMethodThatUsesHandle(c);
    // COMMENT
    d.DoSomethingWithStoredHandle();
}

如果在COMMENT(*)发生垃圾收集怎么办?垃圾收集器可以自由地说“嘿,局部变量c在这种方法中永远不会被引用;我可以积极进取并将其视为死!”。如果终结器运行并且句柄被销毁,那么当最后一个方法运行时,它会访问一个被销毁的句柄并崩溃。

要解决这个罕见但可能出现的问题,您可以使用GC.KeepAlive告诉垃圾收集器在清理特定引用时不那么积极。如果你保持c活着直到方法结束,那么你知道它的析构函数不可能运行。


(*)当然,GC在不同的线程上运行,并且可以随时运行。 GC操作和不可中断操作的详细信息很复杂,您不应该依赖这些实现细节来确保正确性。

答案 1 :(得分:2)

在大多数情况下,您可以使用fixed关键字。

来自Eric Lippert的新blog似乎还有至少两种可能性:

请注意,在这两个选项中,您需要确保正确释放内存。

另一方面,如果您的问题是移动了一小部分内存(导致访问冲突),那么解决方案几乎永远不会禁用整个移动内存的部分。

答案 2 :(得分:1)

我认为您不能在全球范围内执行此操作,但您可以使用fixed关键字来固定特定对象,并获得所需的效果。