2

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

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

我想做的是让 GC 工作,但禁用它移动(碎片整理)内存的部分。

有没有办法做到这一点?

4

3 回答 3

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 可中断和不可中断的操作细节很复杂,您不应依赖这些实现细节来确保正确性。

于 2012-12-30T16:32:29.833 回答
2

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

从 Eric Lippert 的新博客看来,至少还有另外两种可能性:

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

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

于 2012-12-30T10:28:10.340 回答
1

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

于 2012-12-30T10:13:54.347 回答