我正在编写一个程序,在多个线程中调用多个基于C的函数(p / Invoke)。
程序有时会因访问冲突错误而崩溃。我的第一个想法是GC优化了内存并将C函数正在处理的内存块移动到另一个位置。
我想要做的是让GC工作但禁用它移动的部分(defrags)内存。
有办法做到这一点吗?
答案 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
关键字来固定特定对象,并获得所需的效果。