即使内存可用,MemoryFailPoint也会始终引发InsufficientMemoryException [英] MemoryFailPoint always throws an InsufficientMemoryException even when memory is available

查看:119
本文介绍了即使内存可用,MemoryFailPoint也会始终引发InsufficientMemoryException的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I have written the following code to check for sufficient memory,

while (true)
{
    try
    {
        // Check for available memory.
        memFailPoint = new MemoryFailPoint(250);

        break;
    }
    catch (InsufficientMemoryException ex)
    {
        if (memFailPoint != null)
        {
          memFailPoint.Dispose();
        }

        Thread.Sleep(waitSecond * 1000);
    }
}

我正在Windows 7 64位计算机上的控制台应用程序中运行以上命令.

I am running the above in a console application on a Windows 7 64-bit machine.

每10秒钟对此方法进行4次调用.

There are 4 calls every 10 seconds to this method.

最初它可以正常工作,但是在2-3小时后,总会抛出InsufficientMemoryException.我检查了可用内存,它显示超过1 GB.

Initially it works fine, but after 2-3 hours, there is always an InsufficientMemoryException thrown. I checked available memory and it shows more than 1 GB.

我做了很多尝试,但是我找不到原因.

I tried a lot but I was not able to find why this is happening.

以下是堆栈跟踪:

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

没有内部异常.

推荐答案

您可以依靠此方法正常工作,当您要求时,此异常很可能会在32位进程中触发非常 250兆字节.程序运行了一段时间后,很难做到这一点.

You can rely on this method working correctly, this exception is very likely to trip in a 32-bit process when you ask for 250 megabytes. That gets to be difficult to get when the program has been running for a while.

OOM程序从不崩溃",因为您已经消耗了所有可用的虚拟内存地址空间.之所以崩溃,是因为地址空间中没有一个足以容纳分配空间的空洞.您的代码要求一个足够大的洞,以便一次吞下250兆字节.如果没有异常,则可以确保此分配不会失败.

A program never crashes with OOM because you've consumed all available virtual memory address space. It crashes because there isn't a hole left in the address space that's big enough to fit the allocation. Your code requests a hole big enough to allocate 250 megabytes in one gulp. When you don't get the exception that you can be sure that this allocation will not fail.

但是250兆字节是很多,这是一个很大的数组.并且很可能由于称为地址空间碎片"的问题而失败.换句话说,程序通常从几个非常大的漏洞开始,最大的漏洞约为600兆字节.在存储.NET运行时和非托管Windows DLL所使用的代码和数据的分配之间存在可用漏洞.随着程序分配更多的内存,这些漏洞将变得越来越小.它可能会释放一些内存,但不会重蹈覆辙.通常会出现两个,大约是原始孔的一半,并且在中间的某个位置将原始大孔切成两半.

But 250 megabytes is rather a lot, that's a really big array. And is very likely to fail due to a problem called "address space fragmentation". In other words, a program typically starts out with several very large holes, the largest about 600 megabytes. Holes available between the allocations made to store code and data that's used by the .NET runtime and unmanaged Windows DLLs. As the program allocates more memory, those holes get smaller. It is likely to release some memory but that doesn't reproduce a big hole. You typically get two holes, roughly half the size of the original, with an allocation somewhere in the middle that cuts the original big hole in two.

这称为 fragmentation ,这是一个分配和释放大量内存的32位进程,最终导致虚拟内存地址空间碎片化,因此一段时间后仍然可用的最大漏洞变小了, 90兆字节是相当典型的.要求250兆字节几乎可以保证失败.您需要降低目标.

This is called fragmentation, a 32-bit process that allocates and releases a lot of memory ends up fragmenting the virtual memory address space so the biggest hole that's still available after a while gets smaller, around 90 megabytes is fairly typical. Asking for 250 megabytes is almost guaranteed to fail. You will need to aim lower.

毫无疑问,您希望它的工作方式有所不同,从而确保可以保证总计达250 MB的分配的 sum 起作用.但是,这不是MemoryFailPoint的工作方式,它仅检查最大可能的分配.也许不用说,这使它变得无用.否则,我对.NET框架程序员表示同情,使它按我们希望的方式工作既昂贵又不能真正提供保证,因为分配的大小最重要.

You no doubt expected it to work differently, ensuring that the sum of allocations adding up to 250 megabytes is guaranteed to work. This however is not how MemoryFailPoint works, it only checks for the largest possible allocation. Needless to say perhaps, this makes it less than useful. I otherwise do sympathize with the .NET framework programmers, getting it to work the way we'd like it is both expensive and cannot actually provide a guarantee since the size of an allocation matters most.

虚拟内存是非常便宜的大量资源.但是接近消费这一切都是非常麻烦的.一旦消耗了其中的一千兆字节,OOM随机击打的可能性就会越来越大.不要忘记此问题的简单解决方法,因为您正在64位操作系统上运行.因此,仅将EXE平台目标更改为AnyCPU即可获得大量虚拟地址空间.取决于OS版本,但是可能达到1 TB.它仍然是碎片,但您不再关心,漏洞很大.

Virtual memory is a plentiful resource that's incredibly cheap. But getting close to consuming it all is very troublesome. Once you consume a gigabyte of it then OOM striking at random is starting to get likely. Don't forget the easy fix for this problem, you are running on a 64-bit operating system. So just changing the EXE platform target to AnyCPU gets you gobs and gobs of virtual address space. Depends on the OS edition but a terabyte is possible. It still fragments but you just don't care anymore, the holes are huge.

最后但并非最不重要的,在注释中可见,此问题与RAM无关.虚拟内存与您拥有多少RAM完全无关.将虚拟内存地址映射到RAM中的物理地址是操作系统的工作,它是动态进行的.访问内存位置可能会导致页面错误,操作系统将为该页面分配RAM.反过来,当其他地方需要页面时,操作系统会取消映射该页面的RAM.您永远不会用完RAM,在这种情况发生之前,计算机将变慢以进行爬网. SysInternals的VMMap实用程序很好地查看了程序的虚拟地址空间的外观,尽管您可能会在一个大的过程中淹没在信息中.

Last but not least, visible in the comments, this problem has nothing to do with RAM. Virtual memory is quite unrelated to how much RAM you have. It is the operating system's job to map virtual memory addresses to physical addresses in RAM, it does so dynamically. Accessing a memory location may trip a page fault, the OS will allocate RAM for the page. And the reverse happens, the OS will unmap RAM for a page when it is needed elsewhere. You can never run out of RAM, the machine will slow down to a crawl before that can happen. The SysInternals' VMMap utility is nice to see what your program's virtual address space looks like, albeit that you tend to drown in the info for a large process.

这篇关于即使内存可用,MemoryFailPoint也会始终引发InsufficientMemoryException的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆