我怎样才能在.net中一个OutOfMemoryException?net、OutOfMemoryException

2023-09-03 08:00:54 作者:好像把你灌满我的喉

在内存饥饿的应用程序我开发我面临OutOfMemoryExceptions。我希望永远不会有这种虚拟内存异常。为什么如果需要更多的RAM比可用OS没有使用HD作为RAM?

In a memory hungry app I'm developing I'm facing OutOfMemoryExceptions. I expected to never have this kind of exceptions with virtual memory. Why if it is needed more RAM than available the OS is not using the HD as RAM?

推荐答案

您可以在许多不同的方式一个OutOfMemoryException。在32位Windows,一个进程可以使用的2GB的的虚拟地址空间的(我相信这是1TB的64位应用程序)。请记住,这是的没有的RAM,这是完全不同的,因此,虚拟。所以,不要担心内存。所有这一切RAM的作用是使事情更快。 Windows内存管理决定,如果你的程序正在使用的内存会在内存或硬盘。当你有很多的项目开放,更少的内存加载到物理内存和更多的将是在磁盘上。你的表现将是可怕的,但你不会有一个OOM异常。

You can get an OutOfMemoryException in many different ways. In 32-bit windows, a process can use 2GB of virtual address space (I believe it's 1TB in 64-bit applications). Keep in mind this is not RAM, it is completely different, hence "virtual". So forget about RAM. All that RAM does is make things quicker. The windows memory manager decides if the memory your program is using will be in RAM or disk. When you have lots of programs open, less memory is loaded into physical RAM and more will be on disk. Your performance will be terrible, but you won't have an OOM exception.

要得到一个OOM异常在.NET中最常见的方式,就是尽量分配一个足够大的数据量(类似于一个字节数组)的地方没有足够的连续的页面的记忆可来图吧,这是我怀疑你的问题所在。这意味着,有可能得到一个内存溢出异常,即使你请求,将增加虚拟地址空间金额超过2GB的新对象。

The most common way to get an OOM exception in .NET, is to try to allocate a large enough amount of data (something like a byte array) where there is not enough contiguous pages of memory available to map it, which is where I suspect your problem lies. This means that it's possible to get an out of memory exception, even if you're requesting a new object that would increase the virtual address space to an amount over 2GB.

别急!的,有人可能会说,当垃圾收集器运行,内存被压缩,所以总有在堆的结束连续空间!

"But wait!", one might say, "When the garbage collector runs, the memory is compacted, so there's always contiguous space at the end of the heap!"

这是真实的,在大多数情况下。 GC将收集堆,这才能真正被认为是两个堆,小对象堆(SOH),并将其从大对象堆(LOH)。大多数的对象,因为他们是相当小的,将生活中的主要代堆。然而,如果对象是超过一定大小阈值(这是85K,但可能有变化),则代替分配在陆

That is true, for the most part. The GC will collect from the heap, which can really be thought of as two heaps, the Small Object Heap (SOH) and them from the Large Object Heap (LOH). Most objects, since they're fairly small, will live in the main generational heap. However, if the object is above a certain size threshold (this was 85K, but may have changed), it is instead allocated on the LOH.

当内存是从LOH回收,它的没有的压实像SOH。这将是太昂贵了LOH的内存被压缩。内存分配是够贵的,因为它是和应用程序的性能会受到影响。这意味着你堆可以而且经常会出现碎片(这已经在.NET的4.0运行时大大得到了提高,VS 2.0兼容的版本)。

When memory is reclaimed from the LOH, it is not compacted like the SOH. It would be far too expensive for the memory in the LOH to be compacted. Memory allocation is expensive enough as it is, and application performance would suffer. This means that your heap can and often does, become fragmented (this has been improved greatly in .NET's 4.0 runtime, vs 2.0 compatible versions).

比方说,你的LOH堆看起来像这样先于GC:

* = object
- = free space

|**|***|*|**|*|******|****|**|*****|*******|**|*|***|*****|***|**|--
 ^        ^  ^                ^             ^        ^         ^  marked for GC

它看起来像这样一次的完全的GC已经做了:

it will look like this once a full GC has been done:


* = object
- = free space

|--|***|*|-- -|******|****|**|-----|*******|--|*|***|-----|***|----

现在我想 ******** 长分配的数组。运行时会尝试找到一个地方在那里它可以适合。它没有。什么是运行时怎么办?好吧,假设上述复试presents整个2GB的虚拟空间,并没有更多的内存可分配,一个OOM将引发异常。您的有无的空闲页的内存,但不是的不够,是连续的。

Now I want to allocate an array ******** long. The runtime is going to try to find a spot in there where it can fit. It doesn't. What does the runtime do? Well, assuming that the above represents your entire 2GB virtual space and no more memory can be allocated, an OOM exception will be thrown. You have free pages of memory, but not enough that are contiguous.

我不知道你的应用程序做,但这里有一些事情要检查:

I have no idea what your application does, but here are a few things to check:

您在静态的类型成员分配大阵?只要静态成员指向一个对象,它永远不会是GC'd,即使你不要再使用它。静态成员居住类型的对象,并在AppDomain被卸载时,他们才会被释放掉。

Are you allocating large array in static type members? As long as the static member points to that object, it will never be GC'd, even if you don't use it again. Static members live on the type object, and they are only freed when the AppDomain is unloaded.

您是否获得基于用户或其他输入分配大小?如果,例如,你正在阅读的文件头,告诉您一个条目的长度,你验证该条目的大小是正确的?我碰到过接一个的错误我自己,我在一个文件中读取错误的地址,并试图分配2TB内存。验证疯狂。

Are you getting a allocation size based on user or other input? If, for example, you are reading a file header that tells you the length of an entry, are you verifying that the size of the entry is correct? I've run into off-by-one errors myself, I've read the wrong address in a file and tried to allocate 2TB of memory. Verify that madness.

如果您分配大的数组,你的真正的需要?将数据加载到内存中并不能保证你的表现会增加。请记住,你的程序分配的虚拟内存空间,不是RAM。如果你正在阅读的文件,你挑选,你完全读入内存,哪些是你流哪些选择?

If you are allocating large arrays, do you really need to? Loading data into memory doesn't guarantee that your performance will increase. Keep in mind your program is allocated virtual memory space, not ram. If you are reading a file, are you picking and choosing which ones you read completely into memory and which ones you're streaming?

还有的仅仅是几件事我能想到的,它肯定不是COM prehensive。另一种方式来耗尽内存除了想解决超过地址空间2GB的将是一个完整的页面文件,但这是不太常​​见的。

There's are just a few things I can think of, and it's certainly not comprehensive. Another way to run out of memory besides trying to address more than 2GB of address space would be a full page file, but that's less common.

一些有用的工具:

WinDbg中(包含在Windows SDK,作为Windows调试工具的一部分) - 你可以用它来查看堆的统计数据。我个人最喜欢的是!dumpheap -stat !dumpheap型【类型】。我可以用它来快速找到正在使用大量的内存类型。 玩游戏出现out of memory怎么解决

WinDbg (included in the Windows SDK, as part of debugging tools for windows) - You can use this to view statistics about the heap. A personal favorite of mine is !dumpheap -stat and !dumpheap -type [type]. I can use that to quickly find types that are using a lot of memory.

CLRProfiler - 更容易使用比WinDbg的,用量少的特点。它给你一个伟大的图形看看内存分配,你甚至可以看到有多少GC手柄被留在应用程序退出。该图是由彩色型,所以它给你什么类型的使用的是内存中的堆的概览。

CLRProfiler - Easier to use than WinDbg, with less features. It gives you a great graphical look at memory allocations, and you can even see how many GC handles were left when the application exited. The graph is colored by type, so it gives you an overview of what types are using the most memory in your heap.