【问题标题】:Can you repro this 64-bit .NET 4 GC bug?你能重现这个 64 位 .NET 4 GC 错误吗?
【发布时间】:2010-10-19 09:57:50
【问题描述】:

更新:Microsoft 现已重现该错误并正在努力修复。

在评估 .NET 平台在低延迟软件开发方面的可行性时,我们发现了 .NET 4 并发工作站垃圾收集器中的一个严重错误,该错误可能导致应用程序一次挂起长达几分钟。

在我们的三台机器上,以下简单的 C# 程序会导致 GC 泄漏内存,直到没有剩余内存为止,然后启动一个庞大的 GC 循环,在回收 11Gb 堆的同时将程序停顿几分钟(!):

    static void Main(string[] args)
    {
        var q = new System.Collections.Generic.Queue<System.Object>();
        while (true)
        {
            q.Enqueue(0);
            if (q.Count > 1000000)
                q.Dequeue();
        }
    }

您需要在带有 .NET 4 的 64 位 Windows 操作系统上针对 x64 进行编译,并使用默认(交互式)延迟设置在默认(并发工作站)GC 下运行。

这是在这台机器上运行此程序时任务管理器的外观:

请注意,当此程序需要不超过 100Mb 的内存时,这里会泄漏 11Gb 的堆。

我们现在已经积累了大约十几个这个错误的重现,用 F# 和 C# 编写,它似乎与 GC 写入屏障中的一个错误有关,当大部分 gen0 幸存下来时。但是,微软尚未能够复制它。你可以吗?如果是这样,您能否尽可能准确地描述您的设置,以便我们可以尝试准确缩小此错误出现所需的条件。

【问题讨论】:

  • 使用 serverGC 会发生什么?
  • .NET 内存性能计数器显示什么?
  • @leppie:使用其他 GC 选项或其他 GC(包括服务器)可以避免该错误。但是,并发工作站 GC 是 Microsoft 提供的稳定状态的唯一低延迟选项,我们想要低延迟。当然,服务器 GC 的延迟通常要差得多。微软对他们的 GC 算法很腼腆,但我相信服务器 GC 是天真的停止世界并行遍历。
  • 恭喜你终于把这个归档为一个正确的错误。
  • @MaryEllenBench:该错误已修复。我不知道错误报告在哪里。我刚刚写信给微软的 Maoni Stephens,她立即修复了它。

标签: .net garbage-collection


【解决方案1】:

我无法复制它。我在具有 4 gigs ram 的 x64 上进行了尝试,编译为 ANY。最大内存使用量约为 2.5 gigs。最大 GC 暂停时间约为 1084 毫秒。

这是我的 GC ETW 统计数据的输出。

您还可以按时间获取 GC 事件

您运行的类似跟踪输出可能有助于了解幕后发生的事情。

在 .NET 4.0 中,Windows 事件跟踪 (ETW) 提供框架跟踪信息。这是GC 特有的。

为了获取这些信息,有一个名为PerfView的工具

以下是使用该工具获取 GC 信息的步骤

  1. 以管理员身份启动 cmd.exe,这是收集 ETW 跟踪所必需的
  2. 启动要跟踪的应用程序
  3. 发出命令“PerfMonitor.exe /process:4180 start”,其中 4180 是进程 ID
  4. 让应用运行一段时间
  5. 然后发出“PerfMonitor.exe stop”
  6. 获取报告“PerfMonitor.exe GCTime”的命令。这将生成一个报告并在浏览器中使用 GC 统计信息打开它。

【讨论】:

  • 感谢您对PerfMonitor 的引用。根据该工具,这里最长的暂停时间仅为 618 毫秒,但仔细检查显示,每 60-130 毫秒有 18 毫秒的常规暂停,除了在最长的 618 毫秒 GC 暂停之前有一个巨大的 145 秒间隙。所以我的时间并没有浪费在 PerfMonitor 认为是 GC 暂停上。
  • 微软的 Maoni Stephens 和这个垃圾收集器的作者说“这是一个 GC 暂停。PerfMonitor 没有提供足够的信息来识别它。”。
【解决方案2】:

如果以 64 位运行,在 linqpad 中运行代码确实会导致巨大的内存消耗;以 32 位运行正常。

我有一个 8GB 主内存的 Windows 7 x64 终极安装(照常打补丁);安装了 VS.NET 和其他开发工具,因此可能会有一些奇怪的调试器钩子,这些钩子在其他空白机器上是不存在的。

奇怪的是他们没有复制它。你确定那里没有通信故障吗?

哦,使用“new object()”而不是装箱的值类型会导致同样的问题(不出所料),因此您可能希望从重现案例中删除装箱的混淆因素。

【讨论】:

  • 谢谢! “你确定那里没有通讯故障吗?”也许。我已将 repro 作为 C# 解决方案提供给 MS 的其他人进行测试。 “你可能想去除混杂因素。”好主意,会做的。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-12-26
  • 2022-06-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-07-21
相关资源
最近更新 更多