Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/311.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 即使内存可用,MemoryFailPoint也始终引发InsufficientMemoryException_C#_Memory Management_Memory Leaks_Out Of Memory - Fatal编程技术网

C# 即使内存可用,MemoryFailPoint也始终引发InsufficientMemoryException

C# 即使内存可用,MemoryFailPoint也始终引发InsufficientMemoryException,c#,memory-management,memory-leaks,out-of-memory,C#,Memory Management,Memory Leaks,Out Of Memory,我编写了以下代码来检查是否有足够的内存 while (true) { try { // Check for available memory. memFailPoint = new MemoryFailPoint(250); break; } catch (InsufficientMemoryException ex) { if (memFailPoint != null)

我编写了以下代码来检查是否有足够的内存

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小时后,总会抛出
内存不足异常。我检查了可用内存,它显示超过1GB

我尝试了很多,但我无法找到为什么会发生这种情况

以下是堆栈跟踪:

at System.Runtime.MemoryFailPoint..ctor(Int32 sizeInMegabytes)
at SocketListner.AcceptConnection(IAsyncResult res) in H:\Projects\SocketListner.cs:line 308

没有内部异常。

考虑使用
GC.GetTotalMemory
方法来确定调用之前和之后的可用内存量:

memFailPoint = new MemoryFailPoint(250);
当指定大于当前可用内存量的预计内存分配时,
MemoryFailPoint
构造函数在启动操作之前引发
InsufficientMemoryException
。 像user7116一样,这就是为什么您应该首先检查

此链接中的示例应为您提供一个解决方案:


您还可以查看此msdn博客文章:

您可以依靠此方法正常工作,当您请求250兆字节时,此异常在32位进程中很可能出现。当程序运行了一段时间后,很难实现这一点

程序不会因OOM而崩溃,因为您已经消耗了所有可用的虚拟内存地址空间。它崩溃是因为地址空间中没有足够大的洞来容纳分配。您的代码请求一个足够大的洞,一口就可以分配250兆字节。当您没有得到异常时,您可以确保此分配不会失败

但是250兆字节相当多,这是一个非常大的阵列。并且很可能由于一个称为“地址空间碎片”的问题而失败。换句话说,一个程序通常从几个非常大的洞开始,最大的大约600兆字节。为存储.NET运行时和非托管Windows DLL使用的代码和数据而进行的分配之间存在漏洞。当程序分配更多的内存时,这些洞就会变小。它可能会释放一些内存,但不会产生一个大洞。通常你会得到两个洞,大约是原来的一半,中间有一个位置,把原来的大洞切成两半。 这就是所谓的碎片化,一个分配和释放大量内存的32位进程最终会对虚拟内存地址空间进行碎片化,因此一段时间后仍然可用的最大漏洞会变小,大约90兆字节,这是相当典型的。要求250兆字节几乎肯定会失败。你需要瞄准低一点

毫无疑问,您期望它以不同的方式工作,确保总计250兆字节的分配总量能够保证正常工作。然而这不是MemoryFailPoint的工作方式,它只检查可能的最大分配。也许不用说,这使得它没有什么用处。否则,我确实同情.NET framework程序员,让它以我们希望的方式工作既昂贵又无法提供保证,因为分配的大小最为重要

虚拟内存是一种非常便宜的丰富资源。但是,接近消费这一切是非常麻烦的。一旦你消耗了十亿字节的数据,那么随机攻击的可能性就开始增加。别忘了这个问题的简单解决方法,您运行的是64位操作系统。因此,只要将EXE平台目标更改为AnyCPU,就可以获得大量的虚拟地址空间。取决于操作系统版本,但可以使用TB。它仍然是碎片,但你只是不在乎了,洞是巨大的


最后但并非最不重要的一点是,在评论中可以看到,这个问题与RAM无关。虚拟内存与内存的多少无关。操作系统的任务是将虚拟内存地址映射到RAM中的物理地址,它动态地这样做。访问内存位置可能导致页面错误,操作系统将为页面分配RAM。相反,当其他地方需要某个页面时,操作系统将取消该页面的RAM映射。你永远不会耗尽内存,在这之前机器会减速到爬行状态。SysInternals的VMMap实用程序很高兴看到程序的虚拟地址空间是什么样子的,尽管您往往会淹没在一个大进程的信息中。

内存失败点检查是否有连续的可用内存,如下所述:


您可能会消耗很少的内存,但已经将其碎片化了很多,现在无法分配所需大小的连续内存块。这是典型的几个小时后发生的问题。为了避免这种情况,请为您不断实例化的对象使用一个对象池,这将使正在使用的内存空间更加严格。

您还做了什么来获得此错误?是否有堆栈跟踪可以发布?我已经添加了堆栈跟踪,请重新访问问题“我检查了可用内存”如何?即使有1GB的空闲空间,也可能过于分散,无法分配250Meg。内存中需要有250M的连续可用空间才能成功。不管剩下多少物理内存,甚至虚拟内存。您的进程使用了多少内存?我在资源监视器中查看了您的详细分析和建议。我已经将大小减小到50MB,并对应用程序进行了测试,但是我在64位进行了构建,这样就不会出现OOM异常,正如之前捕获的那样。我不得不说,只是随意将其从250削减到50是相当随机的。重要的是,您选择的数字有一定的真实性,并表示您将需要的内存量。如何知道?一旦数据包被处理,内存应该是空闲的,但在很长一段时间后,数据库就会成为瓶颈