Dot-Net

你能重現這個 64 位 .NET 4 GC 錯誤嗎?

  • September 9, 2021

**更新:**微軟現在已經重現了這個錯誤並正在努力修復。

在評估 .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 的堆。

我們現在已經積累了大約十幾個這個 bug 的 repros,用 F# 和 C# 編寫,當大部分 gen0 倖存時,它似乎與 GC 寫屏障中的一個 bug 有關。但是,微軟尚未能夠複製它。你可以嗎?如果是這樣,您能否盡可能準確地描述您的設置,以便我們可以嘗試準確縮小此錯誤出現所需的條件。

如果以 64 位執行,在 linqpad 中執行程式碼確實會導致巨大的記憶體消耗;以 32 位執行正常。

我有一個帶有 8GB 主記憶體的 Windows 7 x64 終極安裝(照常打更新檔);安裝了 VS.NET 和其他開發工具,因此可能會有一些奇怪的調試器鉤子,這些鉤子在其他空白機器上不存在。

奇怪的是他們還沒有複製它。你確定那裡沒有通訊故障嗎?

哦,使用“new object()”而不是裝箱的值類型會導致相同的問題(不足為奇),因此您可能希望從重現案例中刪除裝箱的混淆因素。

我無法重現它。我在具有 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 統計資訊打開它。

引用自:https://stackoverflow.com/questions/3967176