完成端口线程的 OutOfMemoryException
Posted
技术标签:
【中文标题】完成端口线程的 OutOfMemoryException【英文标题】:OutOfMemoryException from Completion Port Thread 【发布时间】:2018-07-22 19:40:39 【问题描述】:我正在处理来自客户的核心转储。因此,我将无法共享导致错误的代码片段。不过,我希望有人能对如何进一步进行一些提示。
我有一个通过套接字执行通信的应用程序。它打开到多个客户端的连接数。一段时间后,它失败并出现 OutOfMemoryException,即使服务器上有足够的内存并且进程没有超过 32 位的限制。
核心转储中的线程池状态如下所示:
!ThreadPool
CPU utilization: 17%
Worker Thread: Total: 16 Running: 0 Idle: 16 MaxLimit: 1023 MinLimit: 16
Work Request in Queue: 0
--------------------------------------
Number of Timers: 2
--------------------------------------
Completion Port Thread:Total: 29 Free: 0 MaxFree: 32 CurrentLimit: 29
MaxLimit: 1000 MinLimit: 16
29 个完成端口线程中的大多数都会抛出 OutOfMemoryException。
!Threads 输出的一部分如下所示:
0 1 1c548 00390680 2026020 Preemptive 00000000:00000000 0038a7f0 0 STA
2 2 2b770 0039db70 2b220 Preemptive 00000000:00000000 0038a7f0 0 MTA (Finalizer)
6 3 2c080 003ef588 a029220 Preemptive 00000000:00000000 0038a7f0 0 MTA (Threadpool Completion Port)
7 4 22ae4 004067e0 202b020 Preemptive 0F0905F0:00000000 0038a7f0 0 MTA
11 5 1ba94 03a79358 a029220 Preemptive 00000000:00000000 03a99928 0 MTA (Threadpool Completion Port)
12 6 3105c 03a7c138 a029220 Preemptive 00000000:00000000 03a99928 0 MTA (Threadpool Completion Port) System.OutOfMemoryException 016c4bc8
13 7 250f0 03a7c958 a029220 Preemptive 0F5B50BC:00000000 03a99928 0 MTA (Threadpool Completion Port) System.OutOfMemoryException 00ef70fc
14 8 32d9c 03a7d578 a029220 Preemptive 00000000:00000000 03a99928 0 MTA (Threadpool Completion Port) System.OutOfMemoryException 016c896c
15 9 3281c 03a7dd98 a029220 Preemptive 00000000:00000000 03a99928 0 MTA (Threadpool Completion Port) System.OutOfMemoryException 016c2f2c
16 10 1c360 03a7e7c0 a029220 Preemptive 00000000:00000000 03a99928 0 MTA (Threadpool Completion Port) System.OutOfMemoryException 016bc434
17 11 240ac 03a815f0 a029220 Preemptive 00000000:00000000 03a99928 0 MTA (Threadpool Completion Port) System.OutOfMemoryException 016bb198
18 12 250fc 03a8fcd0 21220 Preemptive 00000000:00000000 0038a7f0 0 Ukn
19 13 30f1c 03ab4fb0 102a220 Preemptive 00000000:00000000 0038a7f0 0 MTA (Threadpool Worker)
20 14 1a034 03ae9210 202b020 Preemptive 0F625BB8:00000000 03a99928 0 MTA
21 15 1f3bc 03ae49b8 202b220 Preemptive 00000000:00000000 03a99928 1 MTA
22 16 f8d8 03aba8c8 202b020 Preemptive 00000000:00000000 03a99928 0 MTA
23 17 32808 03b10118 a029220 Preemptive 00000000:00000000 03a99928 0 MTA (Threadpool Completion Port) System.OutOfMemoryException 016bb760
24 18 2ee1c 03b0fbd0 a029220 Preemptive 00000000:00000000 03a99928 0 MTA (Threadpool Completion Port) System.OutOfMemoryException 016bc268
25 19 539c 03b0ebf8 a029220 Preemptive 00000000:00000000 03a99928 0 MTA (Threadpool Completion Port) System.OutOfMemoryException 016c6288
26 20 31be8 03b0f140 202b220 Preemptive 00000000:00000000 03a99928 1 MTA
27 21 2e884 03b10660 202b220 Preemptive 00000000:00000000 03a99928 1 MTA
28 22 10934 03b0f688 202b220 Preemptive 00000000:00000000 03a99928 1 MTA
对我来说,这看起来像是一个死锁,消费者停止处理传入套接字的数据,但这只是一个模糊的理论。
你对此有什么想法吗?
【问题讨论】:
虽然this 特定于 ASP.NET,但很多建议(如堆碎片)实际上普遍适用。您真正需要的是完整的用户模式转储(因此包括托管堆中的所有内容),然后应用已知技术来分析 OOM。您似乎已经精通调试器,所以这应该不是一个大问题。这是一个很好的flowchart,可以帮助您入门。 另外,显然,首先对失败的线程进行堆栈跟踪。有可能一个通用的“资源不足”或“无效参数”错误代码被转换为“内存不足”,即使 memory 实际上并不是我们用完的资源(但是例如,某个地方的内核池的一小部分,或固定的句柄缓冲区,或OVERLAPPED
池,或设计者想出的其他任何东西)。找到失败的呼叫将对此有所帮助。
一个好的开始是运行!dumpheap -stat
并查看托管内存使用了多少总空间,包括可用空间。最后一点很重要,因为它可以帮助您评估在碎片中丢失了多少内存空间(如果应用程序执行大量 LOH 分配,这可能是一个问题)
【参考方案1】:
您提到了 x86。由于旧的决定,x86 .NET 应用程序被限制为用户模式虚拟地址空间的大约 2 GiB RAM: https://msdn.microsoft.com/en-us/library/windows/desktop/aa366778.aspx#memory_limits
有一个开关可以使用 IMAGE_FILE_LARGE_ADDRESS_AWARE 将限制增加到 3 甚至 4 GiB
.NET 内存管理和测量还有其他怪癖,您应该注意:
Do not measure with TaskManager. How the GC works。 Multithreaded servers 需要格外小心。【讨论】:
正如我在问题中提到的,应用程序进程不超过 32 位 (2 GiB) 的限制。奇怪的是 OutOfMemoryException 仅从 Completion Port Threads 抛出 @Midi 它不超过 2 GiB,因为它未能尝试超过 2 GiB。这就是 OOM 告诉您的:由于碎片化或限制,您必须超过 2 GiB(或 3 或 4)。威奇不工作。而是抛出 OOM。以上是关于完成端口线程的 OutOfMemoryException的主要内容,如果未能解决你的问题,请参考以下文章