具有许多C++ Interop调用的自动C#垃圾收集器性能较差

JDi*_*teo 2 .net c# c++ interop garbage-collection

什么可能导致C#垃圾收集失败如此悲惨地在我的C#应用​​程序执行大量的C++调用时放置好GC.Collect解决问题?我的C#应用​​程序,使数以百万计的C++调用使用System.Runtime.InteropServices的DllImport和CallingConvention.Cdecl,并有一些C#析构函数释放一些C++非托管内存.我正在使用.NET Framework 4.

  1. 什么可能导致我的应用程序中的下面的代码强制进行分页,从而减慢执行到爬行(在我的32 GB系统上消耗29GB的RAM并且在我终止进程之前花费超过4分钟),同时仅更改ManualGCtrue大写的内存使用量大约600MB,执行在29秒内完成?

  2. 为什么离开ManualGC false并改变Writetrue约12 GB封顶内存使用和允许执行在约59秒内完成,而不分页?

我的应用程序中的一些代码片段(显然有些名称已更改):

private static int callCount = 0;
private const bool ManualGC = false;
private const bool Write    = false;

internal static void CommonlyCalled()
{
    ++callCount;

    if ( callCount % 100000 == 0)
    {
        if (ManualGC)
        {
            GC.Collect();
            GC.WaitForPendingFinalizers();
        }
        if (Write) Console.WriteLine(HandleErrorsCallCount);
    }

    DoLogic();
}
Run Code Online (Sandbox Code Playgroud)

使用Windows任务管理器中的"内存(专用工作集)"列测量内存.行为始终是可重复的.

Han*_*ant 7

并有一些C#析构函数来释放一些C++非托管内存

如果您的包装器很小并且您的C++代码需要大量内存,那还不够.你只是没有给GC施加足够的压力让它尽快给你的终结者打电话.实现IDisposable来解决这个问题是样板.但不是一个完整的解决方案,你应该告诉GC,以便它可以做些什么.一些代码可以使用:

using System;
using System.Runtime.InteropServices;

class Program {
    static void Main(string[] args) {
        while (!Console.KeyAvailable) {
            new Wrapper();
        }
    }
}

class Wrapper {
    private const int alloc = 10 * 1024;    // C++ object memory usage
    private readonly bool useamp = false;   // Change this after testing
    private IntPtr mem;

    public Wrapper() {
        if (useamp) GC.AddMemoryPressure(alloc);
        mem = Marshal.AllocHGlobal(alloc);
    }
    ~Wrapper() {
        Marshal.FreeHGlobal(mem);
        if (useamp) GC.RemoveMemoryPressure(alloc);
    }
}
Run Code Online (Sandbox Code Playgroud)

运行它时,请观察该程序的内存使用情况.在我的机器上,私有字节构建大约半个演出.现在改变useamp并重新运行,你会看到它是很多更高效,只需要4 MB.无需调用Dispose :)在Win 8.1,.NET 4.5.1上测试,在较旧的.NET版本上可能会得到非常不同的结果.

你为alloc选择的价值并不重要,它只需要在球场上.显然你确实需要超过10KB.