C# 抑制GC内存优化

C# 抑制GC内存优化,c#,garbage-collection,defragmentation,C#,Garbage Collection,Defragmentation,我正在编写一个程序,在多个线程中调用多个基于C的函数(p/Invoke) 有时,程序会因访问冲突错误而崩溃。我的第一个想法是GC优化了内存,并将C函数正在处理的内存块移到了不同的位置 我想做的是让GC工作,但禁用它移动(碎片整理)内存的部分 有什么方法可以做到这一点吗?我不认为你可以在全局范围内做到这一点,但是你可以使用固定的关键字来锁定特定的对象,达到预期的效果。在大多数情况下,你可以使用固定的关键字 从埃里克·利珀特(Eric Lippert)的新作品来看,似乎至少还有两种可能性: 使用内

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

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

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


有什么方法可以做到这一点吗?

我不认为你可以在全局范围内做到这一点,但是你可以使用
固定的
关键字来锁定特定的对象,达到预期的效果。

在大多数情况下,你可以使用
固定的
关键字

从埃里克·利珀特(Eric Lippert)的新作品来看,似乎至少还有两种可能性:

  • 使用内存分配
  • 使用外部非托管分配器,如
请注意,在这两个选项中,您需要确保正确释放内存


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

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

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

您可能无法做到这一点,如果您确实设法使其几乎正常工作,那么它将是特定于实现的。(例如,它在Mono上就不起作用了)。移动实时数据是复制分代垃圾收集器的基本属性。至少阅读您是否知道可以在P/Invoke场景中固定内存?在调用C函数之前,我使用P/Invoke和AllocHGGlobal来固定对象。我还是时不时地撞车。当我在调试中运行程序时,没有崩溃。在调试和发布模式下,有没有一个地方可以让我了解GC操作的区别?老实说,听起来你的问题与GC完全无关。这听起来更像是代码中的一个基本线程错误。调试构建不会显著改变GC的行为(如果有的话),但会改变几乎所有其他内容的行为。这可能值得考虑。在将对象发送到C函数之前,我会先锁定它们。我仍然时常遇到崩溃。@Gilad那么您应该通过找出崩溃的原因来修复错误,而不是试图通过限制GC来解决它。我不是试图解决它,而是试图验证这就是问题所在。@Gilad您可以在您的p/invoke和出错行周围发布相关代码吗?