zne*_*eak 16 .net c# multithreading garbage-collection
我正在研究将相对较小的服务从C++重写为C#的可能性.该服务有两个主要功能:
实时任务由一个单独的库处理,该库执行自己的线程,并且根本不与服务的其余部分进行交互.服务的其余部分每5分钟左右从HTTP请求中获取一些数据.
问题是,由于实时部分有很长的期限,我无法真正容忍库的线程上的GC暂停.在我自己的代码方面,GC应该有足够的时间在Web请求之间运行,但我不能容忍它在我尝试将数据提供给库时启动.
我发现我可以创建一个垃圾收集器不会开始使用的关键部分GC.TryStartNoGCRegion(),这解决了一半的问题.
但是,我仍然不知道是否有办法告诉.NET GC单独留下不运行托管代码的特定线程.那可能吗?
正如您所指出的,当应用程序配置为在工作站 GC 模式下运行时,垃圾收集器不会挂起执行本机代码的线程。在这种情况下,只要您的服务收到请求,我就会尝试这样的事情......
    private bool _running = true;
    private int _workCounter = 0;
    private AutoResetEvent _workFlag = new AutoResetEvent(false);
    private void RunNoGCNativeCode(params object[] args)
    {
        // Increase the work counter to determine how many requests are being processed
        if (Interlocked.Increment(ref _workCounter) == 1)
        {
            // Try to start a No GC Region
            GC.TryStartNoGCRegion(1 * 1024 * 1024 * 1024, true);
        }
        // TODO: Prep data and execute your native code
        // TODO: Process response
        // TODO: Dispose of anything that is no longer in use and null objects as needed
        if (Interlocked.Decrement(ref _workCounter) == 0 && GCSettings.LatencyMode == GCLatencyMode.NoGCRegion)
        {
            GC.EndNoGCRegion();
        }
        // Notify Manual Collection thread work has been completed
        _workFlag.Set();
    }
Run Code Online (Sandbox Code Playgroud)
在不同的线程上...
    private void WaitForNoWorkThenGC()
    {
        // Continue running thread while in use
        while (_running)
        {
            // Wait for some work to be complete
            _workFlag.WaitOne();
            // If there is no work being processed call GC.Collect() 
            if (_workCounter == 0)
            {
                GC.Collect();
            }
        }
    } 
Run Code Online (Sandbox Code Playgroud)
这应该可以帮助您控制 GC 发生的时间,以尽量减少对应用程序的影响
至于托管代码,我没有发现任何迹象表明 .NET 垃圾收集可以“不理会”执行托管代码的特定线程。所有当前的垃圾收集模式(服务器、工作站、并发等)将在选择时暂停执行托管代码的所有线程。请注意,某些 GC 模式可以在线程中具有较短的暂停时间,这也可能有所帮助。我也尝试在实时 C# 应用程序中使用 TryStartNoGCRegion() ,它总是忽略我的请求,因为我使用的内存量,我找不到一种方法来指定仅在达到 X 内存限制后进行收集。
不过,您可以研究两种潜在的解决方案。