--- tags: docker, memory, leak --- # [Docker] .NetCore Memory Usage Abnormal 最近觀察到服務的記憶體以飛快的速度不正常的增加, ![](https://i.imgur.com/D94j0hZ.png) 與相同的服務部屬在 Window Server,平均記憶體使用量只有落在 2G左右 ## 嘗試1 原本懷疑是 MemoryCache的問題,於是寫一個 job定時印出目前的 CacheKey。 但是觀察一天後 CacheKey Size並沒有如預期的增加。 ```csharps= while (!stoppingToken.IsCancellationRequested) { var memoryCache = MemoryCache.Default; var keyValuePairs = memoryCache.ToList(); var keyPairsContext = keyValuePairs.OrderBy(x => x.Key) .Select(x => new { Key = x.Key, Value = x.Value.ToString() }); _logger.LogDebug($"MemoryCache Count : {keyValuePairs.Count}, Key-Pairs : {keyPairsContext.ToJson()}"); await Task.Delay(TimeSpan.FromMinutes(10), stoppingToken); } ``` ## 嘗試2 後來在 MSDN上看到如何偵錯 Memory Leak的辦法。 偵錯的過程需要使用 dotnet-dump以及一些包含在 SDK的工具,所以我們將 base image換成 mcr.microsoft.com/dotnet/sdk:6.0 以及安裝以下工具 ```dockerfile= RUN apt-get update RUN apt-get install -y htop RUN mkdir /root/.dotnet/tools -p RUN dotnet tool install --global dotnet-dump ``` 部屬完成後,我們透過指令進去 Container ``` docker exec -ti ContainerId bash ``` 由於 dotnet tool安裝工具時,沒有將指令加入環境變數入,所以我們要手動切換路徑 ```bash= cd /root/.dotnet/tools ``` 此時可以執行 htop,叫出工作管理員來取得 process id。 我們可以看到有很多名稱一模一樣的 process,其中 id最小的 process就是 main process,也就是我們要觀察的對象。 (一般來說,在 Docker中也只會有一個 process,可以將 ProcessId默認為 1) ![](https://i.imgur.com/D4vS1FX.png) 然後我們執行 dump mempry的語法並開始分析記憶體的使用情況 ```bash= ./dotnet-dump collect -p ProcessId ./dotnet-dump analyze FileName dumpheap -stat ``` ![](https://i.imgur.com/Qqj89Kz.png) 此時我們可以看到整個記憶體的分配及使用狀況,此時 free block已經占用了 1279943192 KB(約等於 1.2GB),且隨著時間推移, free block增長的狀況與占用的記憶體正好一致 ![](https://i.imgur.com/iafcKCg.png) ## 解法 新增一個 Job定時去執行 GC並壓縮記憶體空間,讓閒置的記憶體空間可以釋放給 OS ```csharp= GCSettings.LargeObjectHeapCompactionMode = GCLargeObjectHeapCompactionMode.CompactOnce; GC.Collect(); ``` ![](https://i.imgur.com/7E1FZxW.png) ![](https://hackmd.io/_uploads/BJecMIJto2.png) ## 你必須知道的 .Net 這本書對於記憶體的分配,GC的運作等等都有詳盡的描述。 --- ## Reference [Debug a memory leak in .NET Core](https://learn.microsoft.com/en-us/dotnet/core/diagnostics/debug-memory-leak) [GCSettings.LargeObjectHeapCompactionMode Property](https://learn.microsoft.com/en-us/dotnet/api/system.runtime.gcsettings.largeobjectheapcompactionmode?view=net-6.0) [黑大部落格 - 記憶體管理探索(1)](https://blog.darkthread.net/blog/managed-heap-study/) [黑大部落格 - 記憶體管理探索(2)](https://blog.darkthread.net/blog/oom-with-adequate-memory/)