在 Linux 下运行时,我发现 dotnet 应用程序的内存使用率极高。内存也永远不会被释放。 当用户使用我的网络应用程序时,他们确实需要大量内存(1-2 GB 来运行报告),但当他们关闭选项卡时,资源就会被释放,我希望 dotnet 在某种程度上也能做到这一点。
我的 dotnet 应用程序的内存使用率接近 90-95%。
root@a9f25bad2d02:~/site/wwwroot# dotnet-counters monitor
[System.Runtime]
% Time in GC since last GC (%) 0
Allocation Rate (B / 10 sec) 209,648
CPU Usage (%) 0
Exception Count (Count / 10 sec) 0
GC Committed Bytes (MB) 105
GC Fragmentation (%) 43.752
GC Heap Size (MB) 68
Gen 0 GC Count (Count / 10 sec) 0
Gen 0 Size (B) 19,577,728
Gen 1 GC Count (Count / 10 sec) 0
Gen 1 Size (B) 1,608,856
Gen 2 GC Count (Count / 10 sec) 0
Gen 2 Size (B) 49,073,776
IL Bytes Jitted (B) 4,471,180
LOH Size (B) 26,161,384
Monitor Lock Contention Count (Count / 10 sec) 0
Number of Active Timers 15
Number of Assemblies Loaded 5,110
Number of Methods Jitted 64,067
POH (Pinned Object Heap) Size (B) 706,440
ThreadPool Completed Work Item Count (Count / 10 sec) 17
ThreadPool Queue Length 0
ThreadPool Thread Count 4
Time spent in JIT (ms / 10 sec) 0
Working Set (MB) 5,773
root@a9f25bad2d02:~/site/wwwroot# free -m
total used free shared buff/cache available
Mem: 7817 6858 121 19 837 740
Swap: 4095 2156 1939
root@a9f25bad2d02:~/site/wwwroot# top
Tasks: 11 total, 2 running, 8 sleeping, 1 stopped, 0 zombie
%Cpu(s): 1.5 us, 0.7 sy, 50.4 ni, 45.3 id, 2.2 wa, 0.0 hi, 0.0 si, 0.0 st
MiB Mem : 7817.4 total, 89.3 free, 7262.5 used, 465.6 buff/cache
MiB Swap: 4096.0 total, 1676.2 free, 2419.8 used. 341.3 avail Mem
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
74 root 30 10 9812340 5.4g 19812 t 0.0 70.7 21:22.97 dotnet
1908 root 30 10 13948 708 540 S 0.0 0.0 0:00.18 sshd
1910 root 30 10 5752 2040 1808 S 0.0 0.0 0:00.03 bash
2526 root 30 10 9780 3448 2972 R 0.0 0.0 0:00.00 top
正如您从
dotnet-counters monitor
中看到的,工作集约为 5.7 GB,而所有代以及大型和固定对象堆使用的字节总数仅约为 120 Mb。
这得到了对大小为 5 GB 的内存转储的分析的证实。
dotnet-counters collect
运行应用程序并模拟典型用户负载。我已在下面按时间绘制了 GC Committed Bytes
的结果。我的问题的根本原因与我的应用程序或事件 dotnet 无关 - 它与
glib malloc
有关。 malloc 中会动态调整内存分配块的大小,当应用程序使用大量内存时,会发生碎片并且内存会被勉强释放。可以在这里找到更好的文章:https://github.com/dotnet/runtime/issues/13301#issuecomment-535641506
这不仅影响我,dotnet 之外的其他程序也会受到影响。例如,
似乎有 2 个解决方法,要么修复
glibc.malloc.trim_threshold
的大小以阻止其动态,要么通过 glibc.malloc.arena_max
减少竞技场数量,因为默认数量为 8 * NumOfCores
。更多信息可以在这里找到:https://www.gnu.org/software/libc/manual/html_node/Memory-Allocation-Tunables.html
最终我选择设置环境变量
MALLOC_TRIM_THRESHOLD_=131072
这解决了我的问题。
在 Azure 中,您可以方便地使用配置来执行此操作,
我可以确认是通过 bash 设置的,
kudu_ssh_user@ff3d088f400d:/$ env | grep MALLOC
APPSETTING_MALLOC_TRIM_THRESHOLD_=131072
MALLOC_TRIM_THRESHOLD_=131072
现在我可以在我的 Web 应用程序中看到内存被释放😅,