我们有一个泄漏内存的32位Windows服务 - 抛出OutOfMemory异常。它是在Windows Server 2003上运行的.net 4.0可执行文件。在使用WinDbg调试崩溃转储文件时,我看到大部分内存实际上是保留的而不是提交的。
从WinDbg屏幕截图中可以看出,存在2.5 Gb的未分类内存使用情况,其中大部分2.1 Gb实际上是保留内存(MEM_RESERVE)。我有调试压缩转储的经验,但这种情况对我来说是新的。 MEM_COMMIT退出OK - 564.270 Mb,托管堆的大小为82 Mb
我还查看了原生堆,看看是否保留了大块数据,但无法找到任何可疑的数据
所以我的问题是 - MEM_RESERVED可能会导致OOM异常吗?如果是这样,我该如何调试它,看看为什么/如何保留大量的内存?还有什么地方可以找到可能存在的问题?
如果需要任何其他信息,请提出要求,我会更新我的帖子。
答案 0 :(得分:6)
是的,保留记忆可以触发OutOfMemoryException
。尝试分配几个非常大的字节数组。在写入数组内容之前,不会提交这些内存。但是,只需分配这些数组就可以轻松触发OOM。
我不知道实现细节,但由于如果VirtualAlloc无法遵守保留请求,它将失败,我假设CLR将此转换为异常。我不知道如何将失败的预留请求变成有用的东西,所以异常是明智的选择。
答案 1 :(得分:3)
OutOfMemoryException
。保留的内存是虚拟内存,因此可以达到该限制。
您最容易在C ++中尝试:
while(::VirtualAlloc(NULL, 65536, MEM_RESERVE, PAGE_READWRITE) != NULL );
std::cout << "All memory reserved. Now check with tools." << std::endl;
如果VirtualAlloc()返回NULL,则无法分配更多memoy。在WinDbg中,这将显示
MEM_RESERVE 32307 7f6f2000 (1.991 Gb) 99.59% 99.56%
但是,VirtualAlloc()不会在堆上分配内存,因此!heap
在这种情况下没用,只显示默认进程堆:
0:000> !heap
Index Address Name Debugging options enabled
1: 00440000
反过来说:堆mamanger使用VirtualAlloc()来获取内存。另请注意, .NET也不使用堆管理器。它还使用VirtualAlloc()直接分配内存,然后自行管理它。因此,因为您可以在!heap
的输出中看到它,这不是.NET问题,它是本机内存问题。
在我天真的理解中,gflags
设置Enable heap tagging by DLL应该有助于确定堆分配的来源。但是,我期望命令!heap -t
只显示分配内存的DLL的名称并未实现。