保留内存是不是会导致内存不足异常
Posted
技术标签:
【中文标题】保留内存是不是会导致内存不足异常【英文标题】:Can reserved memory cause an Out Of memory exception保留内存是否会导致内存不足异常 【发布时间】:2014-06-07 08:25:49 【问题描述】:我们有一个 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 异常?如果是这样,我该如何调试它,看看为什么/有多少内存被保留?您还会在哪里寻找可能存在的问题?
如果需要任何其他信息,请询问,我会更新我的帖子。
【问题讨论】:
【参考方案1】:是的,保留内存可以触发OutOfMemoryException
。尝试分配几个非常大的字节数组。在您写入数组的内容之前,不会提交这些内存。但是,只需分配这些数组,您就可以轻松触发 OOM。
我不知道实现细节,但由于如果 VirtualAlloc 不能满足保留请求,它将失败,我假设 CLR 将其转换为异常。我看不出它如何将失败的预留请求变成有用的东西,所以例外是一个明智的选择。
【讨论】:
感谢回复,你知道我怎么能看到WinDbg中保留了这么大的内存吗? 假设内存被托管对象使用,您可以使用!dumpheap
和!do
检查这些内存。但是,鉴于!eeheap
的输出显示托管堆很小,我假设其他东西保留了此内存。
你能指定还有什么可以保留内存吗?我很困惑,因为我希望“某物”要么在托管堆上,要么在本机堆上的一些本机资源上——它们都没有指向任何可疑的东西。还有什么可以保留内存?我很乐意立即检查。
我的意思是“本地”。正如我所说,如果保留内存支持托管对象,您将能够在托管堆上找到这些对象。由于这似乎不是本机库或运行时本身的候选者,但我不能肯定地说。您可以通过查看!eeheap
的输出来获取有关 CLR 分配的更多信息。【参考方案2】:
OutOfMemoryException
如果系统无法为您的应用程序分配更多虚拟内存,则会发生。保留内存是虚拟内存,因此会受到该限制。
您可以最轻松地在 C++ 中尝试:
while(::VirtualAlloc(NULL, 65536, MEM_RESERVE, PAGE_READWRITE) != NULL );
std::cout << "All memory reserved. Now check with tools." << std::endl;
如果 VirtualAlloc() 返回 NULL,它不能分配更多的内存。在 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
反之亦然:堆管理器使用 VirtualAlloc() 来获取内存。另请注意,.NET 也不使用堆管理器。它还使用 VirtualAlloc() 直接分配内存,然后自行管理。因此,因为您可以在 !heap
的输出中看到它,所以这不是 .NET 问题,而是本机内存问题。
在我的幼稚理解中,gflags
设置 Enable heap tagging by DLL 应该有助于确定堆分配的来源。然而,我期望命令!heap -t
会简单地显示分配内存的DLL 的名称并没有实现。
【讨论】:
感谢您的意见。我试过 !heap -t 命令,但它没有提供任何有用的东西。我正在尝试挖掘本机内存,看看我能在那里找到什么。非常欢迎任何其他检查其他内容的建议。以上是关于保留内存是不是会导致内存不足异常的主要内容,如果未能解决你的问题,请参考以下文章