我正在编写一个程序,它在多线程中调用多个基于C的函数(p/Invoke)。
有时,程序会因访问冲突错误而崩溃。我的第一个想法是GC优化了内存,并将C函数正在处理的内存块移动到不同的位置。
我想要做的是让GC工作,但禁用它移动(碎片整理)内存的部分。
有没有办法做到这一点?
发布于 2012-12-31 00:32:30
正如其他答案所说,要做的第一件事是确保您正确地固定对象。假设你已经这样做了,还会出什么问题呢?
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-30 18:28:10
在大多数情况下,可以使用fixed关键字。
从埃里克·利伯特的新blog来看,至少还有两种可能性:
使用外部非托管分配器(如AllocHGlobal )使用GCHandle分配内存
请注意,在这两个选项中,您需要确保正确释放内存。
顺便说一句,如果您的问题是移动了一小部分内存(导致访问冲突),那么解决方案几乎永远不会禁用整个移动内存部分。
发布于 2012-12-30 18:13:54
https://stackoverflow.com/questions/14089848
复制相似问题