我正在调查 32 位进程中的 OutOfMemoryException, 以下统计数据引起了我的注意(大型 int64 数组):
!dumpheap -stat
........
707b251c 3 692500 System.Int64[]
6fa6b038 72151 2020228 System.Diagnostics.ProcessModule
6fa9b1a0 72151 2308832 System.Diagnostics.ModuleInfo
707fdd04 2404 3223807 System.Byte[]
707faea4 11990 5780152 System.Object[]
707fb37c 9847 16162530 System.Char[]
00c16a88 41026 19281740 Free
707fac04 183726 21698276 System.String
Total 758006 objects
0:000> !DumpHeap /d -mt 707b251c
Address MT Size
02f5b9ec 707b251c 76
02f7c198 707b251c 60
03f40000 707b251c 692364
Statistics:
MT Count TotalSize Class Name
707b251c 3 692500 System.Int64[]
Total 3 objects
0:000> !gcroot 03f40000
Thread 4320:
*** WARNING: Unable to verify checksum for System.ni.dll
1238ea6c 6fbedbd0 System.Net.TimerThread.ThreadProc() [f:\dd\NDP\fx\src\net\System\Net\_TimerThread.cs @ 707]
edi: (interior)
-> 03dc3670 System.Object[]
-> 03f40000 System.Int64[]
Found 1 unique roots (run '!GCRoot -all' to see all roots).
使用.Net Framework 4.8。 为什么TimerThread需要这么大的数组?
转储是由应用程序的“简化”制成的, 初始版本有更剧烈的数字(有更多线程(229 vs 32),应用程序域(~180 vs 0)加载):
!dumpheap -stat
..........
707b251c 387 105384412 System.Int64[]
终于找到了, 不确定 WinDbg 显示的 TimeThread 调用堆栈是否反映了现实,但是 重现它的最简单方法是使用 main 方法运行此类控制台应用程序:
var procs = System.Diagnostics.Process.GetProcessesByName("GetProcessesByName");
Console.ReadKey();
然后获取转储,这在我的案例中显示
!dumpheap -stat
....
6fa595d0 7361 264996 System.Diagnostics.ThreadInfo
6fa595a4 7361 529992
System.Diagnostics.NtProcessInfoHelper+SystemThreadInformation
7061251c 2 1003800 System.Int64[]
Total 19595 objects
所以看来奇怪的行为与 Process.GetProcessesByName 有关。 然而 Process.GetCurrentProcess() 不会在内存中产生任何 int64[] 占用空间。