DOTNET記憶體佔用最佳化

Rick Carter發表於2024-11-08

很長時間以來我都在公司dotnet開發的軟體上做各種效能最佳化,包括各種崩潰、執行緒池資源不足、死鎖、以及很多效能慢的程式碼問題等,類似這種cpu相關問題都比較好查出來。
這個過程中經常遇到記憶體佔用過高的問題,也是各種辦法都試用了一遍,包括DOTNET GC相關的各種配置,還給docker加記憶體限制,但是一直都解決不了,比如以下這些:

  1. 伺服器模式:https://learn.microsoft.com/zh-cn/dotnet/core/runtime-config/garbage-collector#workstation-vs-server
  2. 後臺垃圾回收:https://learn.microsoft.com/zh-cn/dotnet/core/runtime-config/garbage-collector#background-gc
  3. 動態適應應用程式大小 (DATAS):https://learn.microsoft.com/zh-cn/dotnet/core/runtime-config/garbage-collector#dynamic-adaptation-to-application-sizes-datas
  4. 高記憶體百分比:https://learn.microsoft.com/zh-cn/dotnet/core/runtime-config/garbage-collector#high-memory-percent
  5. 節省記憶體:https://learn.microsoft.com/zh-cn/dotnet/core/runtime-config/garbage-collector#conserve-memory

以上全部解決不了問題,透過dump-counters診斷看,GC012代以及LOH等佔用都不高,但是WorkingSet佔用是它們總和的好幾倍,並且長時間保持這個狀態。意思就是程式實際並沒有使用太多記憶體,但是整個程序看記憶體佔用卻很高,似乎GC工作了但並沒有把記憶體釋放回作業系統。透過dump分析記憶體發現大量的空閒記憶體,碎片也沒有那麼多。空閒的記憶體是程式曾經高負載時申請使用的,之後低負載就沒有釋放回作業系統。

搜尋後發現了兩個dotnet的issues:
https://github.com/dotnet/runtime/issues/90640
https://github.com/dotnet/runtime/issues/49317
看來遇到這個問題的不只我一個人,似乎從dotnet7開始就會有這個問題,dotnet8加入的DATAS配置也無法解決這個問題。

按照這個issue說的加這兩個環境變數,驗證發現真的可以解決問題,只是cpu佔用會稍微多點,這個可以接受。

MALLOC_ARENA_MAX: 2
MALLOC_TRIM_THRESHOLD_: 85000

這個問題可能針對的是不太單純的應用程式,會出現有時需要更多記憶體,而常規情況下只需要少量記憶體的情況。

相關文章