保留的内存可能导致Out of memory异常

时间:2014-04-22 19:25:23

标签: .net memory memory-management out-of-memory windbg

我们有一个泄漏内存的32位Windows服务 - 抛出OutOfMemory异常。它是在Windows Server 2003上运行的.net 4.0可执行文件。在使用WinDbg调试崩溃转储文件时,我看到大部分内存实际上是保留的而不是提交的。 enter image description here

从WinDbg屏幕截图中可以看出,存在2.5 Gb的未分类内存使用情况,其中大部分2.1 Gb实际上是保留内存(MEM_RESERVE)。我有调试压缩转储的经验,但这种情况对我来说是新的。 MEM_COMMIT退出OK - 564.270 Mb,托管堆的大小为82 Mb

enter image description here

我还查看了原生堆,看看是否保留了大块数据,但无法找到任何可疑的数据

enter image description here

所以我的问题是 - MEM_RESERVED可能会导致OOM异常吗?如果是这样,我该如何调试它,看看为什么/如何保留大量的内存?还有什么地方可以找到可能存在的问题?

如果需要任何其他信息,请提出要求,我会更新我的帖子。

2 个答案:

答案 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的名称并未实现。