我编写了以下代码来检查是否有足够的内存,
while (true)
{
try
{
// Check for available memory.
memFailPoint = new MemoryFailPoint(250);
break;
}
catch (InsufficientMemoryException ex)
{
if (memFailPoint != null)
{
memFailPoint.Dispose();
}
Thread.Sleep(waitSecond * 1000);
}
}我在Windows7 64位计算机上的控制台应用程序中运行上述代码。
每10秒有4次对此方法的调用。
最初它工作得很好,但2-3个小时后,总是会抛出一个InsufficientMemoryException。我检查了可用内存,它显示超过1 GB。
我尝试了很多,但我无法找到为什么会发生这种情况。
以下是堆栈跟踪:
at System.Runtime.MemoryFailPoint..ctor(Int32 sizeInMegabytes)
at SocketListner.AcceptConnection(IAsyncResult res) in H:\Projects\SocketListner.cs:line 308没有内部异常。
发布于 2013-06-11 22:53:47
你可以依靠这个方法正确地工作,当你请求250兆字节的时候,这个异常是很可能在32位进程中出错。当程序已经运行了一段时间后,这就很难实现了。
一个程序永远不会因为OOM而崩溃,因为你已经消耗了所有可用的虚拟内存地址空间。它崩溃是因为在地址空间中没有留下足够大的空洞来容纳分配。你的代码请求一个足够大的洞,一口就能分配250兆字节。当你没有得到异常的时候,你可以确定这个分配不会失败。
但是250兆字节是相当多的,这是一个非常大的数组。并且很可能由于被称为“地址空间碎片”的问题而失败。换句话说,一个程序通常从几个非常大的洞开始,最大的大约600兆字节。用于存储.NET运行时使用的代码和数据的分配与非托管Windows DLL之间的可用漏洞。随着程序分配更多的内存,这些空洞会变得更小。它可能会释放一些内存,但这不会重现一个大漏洞。你通常会得到两个洞,大约是原来大小的一半,在中间的某个地方分配一个位置,把原来的大洞切成两半。
这称为碎片,这是一个分配和释放大量内存的32位进程,最终会将虚拟内存地址空间碎片化,因此在一段时间后仍可用的最大空洞会变小,大约为90兆字节,这是相当典型的。请求250兆字节几乎肯定会失败。你需要降低目标。
毫无疑问,您希望它以不同的方式工作,确保分配总和达到250兆字节。然而,这不是MemoryFailPoint的工作方式,它只检查最大可能的分配。也许不用说,这使得它没有什么用处。除此之外,我确实同情.NET框架程序员,让它以我们希望的方式工作既昂贵又不能真正提供保证,因为分配的大小是最重要的。
虚拟内存是一种非常便宜的丰富资源。但是,接近于将其全部消耗是非常麻烦的。一旦你消耗了一千兆字节,那么OOM随机攻击的可能性就开始变得很大。别忘了解决这个问题的简单方法,你是在64位操作系统上运行的。因此,只需将EXE平台目标更改为AnyCPU,就会获得大量的虚拟地址空间。取决于操作系统版本,但有可能达到is级。它仍然是碎片,但你就是不再关心了,漏洞是巨大的。
最后但并非最不重要的是,在评论中可以看到,这个问题与nothing无关。虚拟内存与你有多少内存是完全无关的。操作系统的工作是将虚拟内存地址映射到RAM中的物理地址,它是动态执行的。访问内存位置可能会触发页面故障,操作系统将为该页面分配RAM。反之亦然,当某个页面在其他地方需要时,操作系统会取消它的RAM映射。你永远不会用完内存,在这种情况发生之前,机器会减速到爬行。SysInternals的VMMap实用程序可以很好地查看您的程序的虚拟地址空间,尽管您可能会沉浸在大型进程的信息中。
发布于 2013-06-11 22:36:51
考虑使用GC.GetTotalMemory方法来确定调用之前和之后的可用内存量:
memFailPoint = new MemoryFailPoint(250);当您指定的计划内存分配大于当前可用内存量时,MemoryFailPoint构造函数会在开始操作之前引发InsufficientMemoryException。像user7116 commented一样,这就是为什么你应该首先检查。
此链接中的示例将为您提供解决方案:MemoryFailPoint Class
您也可以查看msdn博客文章:Out of memory? Easy ways to increase the memory available to your program
发布于 2013-06-11 22:55:47
如此处所述,MemoryFailPoint会检查连续可用内存:http://msdn.microsoft.com/fr-fr/library/system.runtime.memoryfailpoint.aspx
您可能只消耗了很少的内存,但是已经将其分割得很多,现在无法分配所需大小的连续内存块。这个问题在几个小时后发生是非常典型的。为了避免这种情况,对你一直在实例化的对象使用一个对象池,这将使使用中的内存空间更加严格。
https://stackoverflow.com/questions/17046463
复制相似问题