为什么我的 C# 应用程序会出现内存不足异常?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/597499/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Why am I getting an Out Of Memory Exception in my C# application?
提问by George2
My memory is 4G physical, but why I got out of memory exception even if I create just 1.5G memory object. Any ideas why? (I saw at the same time, in the performance tab of task manager the memory is not full occupied, and I could also type here -- so memory is not actually low, so I think I hit some other memory limitations)?
我的内存是 4G 物理内存,但是为什么即使我只创建了 1.5G 内存对象也会出现内存不足异常。任何想法为什么?(我同时看到,在任务管理器的性能选项卡中,内存未满,我也可以在这里输入——所以内存实际上并不低,所以我想我遇到了其他一些内存限制)?
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace TestBigMemoryv1
{
class MemoryHolderFoo
{
static Random seed = new Random();
public Int32 holder1;
public Int32 holder2;
public Int64 holder3;
public MemoryHolderFoo()
{
// prevent from optimized out
holder1 = (Int32)seed.NextDouble();
holder2 = (Int32)seed.NextDouble();
holder3 = (Int64)seed.NextDouble();
}
}
class Program
{
static int MemoryThreshold = 1500; //M
static void Main(string[] args)
{
int persize = 16;
int number = MemoryThreshold * 1000 * 1000/ persize;
MemoryHolderFoo[] pool = new MemoryHolderFoo[number];
for (int i = 0; i < number; i++)
{
pool[i] = new MemoryHolderFoo();
if (i % 10000 == 0)
{
Console.Write(".");
}
}
return;
}
}
}
采纳答案by JaredPar
In a normal 32 bit windows app, the process only has 2GB of addressable memory. This is irrelevant to the amount of physical memory that is available.
在普通的 32 位 Windows 应用程序中,该进程只有 2GB 的可寻址内存。这与可用的物理内存量无关。
So 2GB available but 1.5 is the max you can allocate. The key is that your code is not the only code running in the process. The other .5 GB is probably the CLR plus fragmentation in the process.
所以 2GB 可用,但 1.5 是您可以分配的最大值。关键是您的代码不是流程中运行的唯一代码。其他 0.5 GB 可能是 CLR 加上进程中的碎片。
Update:in .Net 4.5 in 64 bit process you can have large arrays if gcAllowVeryLargeObjectssetting is enabled:
更新:在 .Net 4.5 的 64 位进程中,如果启用了gcAllowVeryLargeObjects设置,您可以拥有大型数组:
On 64-bit platforms, enables arrays that are greater than 2 gigabytes (GB) in total size. The maximum number of elements in an array is UInt32.MaxValue.
在 64 位平台上,启用总大小超过 2 GB 的阵列。数组中的最大元素数为 UInt32.MaxValue。
<configuration>
<runtime>
<gcAllowVeryLargeObjects enabled="true" />
</runtime>
</configuration>
回答by uzbones
On a 32-bit Windows Operating system the maximum 'user-mode' memory that a single application can access is 2GB... assuming that you have 4GB of memory on the box.
在 32 位 Windows 操作系统上,单个应用程序可以访问的最大“用户模式”内存为 2GB……假设您的机器上有 4GB 内存。
Unmanaged VC++ Application's memory consumption on windows server
非托管 VC++ 应用程序在 Windows 服务器上的内存消耗
http://blogs.technet.com/markrussinovich/archive/2008/07/21/3092070.aspx
http://blogs.technet.com/markrussinovich/archive/2008/07/21/3092070.aspx
(It's funny you asked this because I asked almost the same thing yesterday...)
(你问这个很有趣,因为我昨天问了几乎同样的事情......)
回答by geofftnz
You've got a max of 2Gb addressable memory as a 32bit app, as the other posters mentioned. Dont forget about overhead. You're creating an array of 93 million objects - if there happens to be 4 bytes of overhead per object that's an extra 350Mb of memory.
正如其他海报所提到的,您拥有最多 2Gb 可寻址内存作为 32 位应用程序。不要忘记开销。您正在创建一个包含 9300 万个对象的数组 - 如果每个对象碰巧有 4 个字节的开销,那就是额外的 350Mb 内存。
回答by KristoferA
Just to add to the previous replies: you can go beyond the 2Gb limit on systems booted with the /3Gb [and optionally userva] boot flags.
补充一下之前的回复:您可以超出使用 /3Gb [和可选的 userva] 引导标志引导的系统的 2Gb 限制。
回答by Marc Gravell
Just additional to the other points; if you want access to a dirty amount of memory, consider x64 - but be aware that the maximum singleobject size is still 2GB. And because references are larger in x64, this means that you actually get a smallermaximum array/list size for reference-types. Of course, by the time you hit that limit you are probably doing things wrong anyway!
只是对其他点的补充;如果您想访问大量内存,请考虑 x64 - 但请注意最大单个对象大小仍为 2GB。并且因为 x64 中的引用更大,这意味着您实际上获得了更小的引用类型的最大数组/列表大小。当然,当您达到该限制时,您可能无论如何都做错了!
Other options:
其他选项:
- use files
- use a database
- 使用文件
- 使用数据库
(obviously both has a performance difference compared to in-process memory)
(显然与进程内内存相比,两者都有性能差异)
Update: In versions of .NET prior to 4.5, the maximum object size is 2GB. From 4.5 onwards you can allocate larger objects if gcAllowVeryLargeObjectsis enabled. Note that the limit for string
is not affected, but "arrays" should cover "lists" too, since lists are backed by arrays.
更新:在 4.5 之前的 .NET 版本中,最大对象大小为 2GB。从 4.5 开始,如果启用了gcAllowVeryLargeObjects,您可以分配更大的对象。请注意,限制string
不受影响,但“数组”也应涵盖“列表”,因为列表由数组支持。
回答by Yort
One more thing to be aware of; some .NET objects require 'contiguous' memory. i.e if you are trying to allocate a large array the system may need not only sufficient free memory in your process but also for all that free memory to be in one big chunk... and unfortunately the process memory gets fragmented over time so this may not be available.
还有一件事要注意;某些 .NET 对象需要“连续”内存。即,如果您尝试分配一个大数组,系统可能不仅需要在您的进程中有足够的可用内存,而且还需要将所有可用内存放在一个大块中......不幸的是,进程内存会随着时间的推移而变得碎片化,因此这可能不可用。
Some objects/data types have this requirement and some don't... I can't remember which ones do, but I seem to recall StringBuilder and MemoryStream have different requirements.
有些对象/数据类型有这个要求,有些没有……我不记得哪些有,但我似乎记得 StringBuilder 和 MemoryStream 有不同的要求。
回答by Shift Technology
Check that you are building a 64-bit process, and not a 32-bit one, which is the default compilation mode of Visual Studio. To do this, right click on your project, Properties -> Build -> platform target : x64. As any 32-bit process, Visual Studio applications compiled in 32-bit have a virtual memory limit of 2GB.
检查您是否正在构建 64 位进程,而不是 32 位进程,这是 Visual Studio 的默认编译模式。为此,请右键单击您的项目,属性 -> 构建 -> 平台目标:x64。与任何 32 位进程一样,以 32 位编译的 Visual Studio 应用程序的虚拟内存限制为 2GB。
Each process has its own virtual memory, called an address space, into which it maps the code that it executes and the data it manipulates. A 32-bit process uses 32-bit virtual memory address pointers, which creates an absolute upper limit of 4GB (2^32) for the amount of virtual memory that a 32-bit process can address. However, the operating system requires half of it (to reference its own code and data), creating a limit of 2GB for each process. If your 32-bit application tries to consume more than the entire 2GB of its address space, it will return “System.OutOfMemory”, even though the physical memory of your computer is not full.
每个进程都有自己的虚拟内存,称为地址空间,它将执行的代码和操作的数据映射到其中。32 位进程使用 32 位虚拟内存地址指针,这为 32 位进程可以寻址的虚拟内存量创建了 4GB (2^32) 的绝对上限。但是,操作系统需要它的一半(引用它自己的代码和数据),为每个进程创建了 2GB 的限制。如果您的 32 位应用程序试图消耗超过其整个 2GB 的地址空间,它将返回“System.OutOfMemory”,即使您计算机的物理内存未满。
64-bit processes do not have this limitation, as they use 64-bit pointers, so their theoretical maximum address space is 16 exabytes (2^64). In reality, Windows x64 limits the virtual memory of processes to 8TB. The solution to the memory limit problem is then to compile in 64-bit.
64 位进程没有这个限制,因为它们使用 64 位指针,所以它们的理论最大地址空间是 16 艾字节 (2^64)。实际上,Windows x64 将进程的虚拟内存限制为 8TB。内存限制问题的解决方案是在 64 位中编译。
However, object's size in Visual Studio is still limited to 2GB, by default. You will be able to create several arrays whose combined size will be greater than 2GB, but you cannot by default create arrays bigger than 2GB. Hopefully, if you still want to create arrays bigger than 2GB, you can do it by adding the following code to you app.config file:
但是,默认情况下,Visual Studio 中对象的大小仍限制为 2GB。您将能够创建多个组合大小大于 2GB 的数组,但默认情况下不能创建大于 2GB 的数组。希望如果您仍然想创建大于 2GB 的数组,您可以通过将以下代码添加到您的 app.config 文件来实现:
<configuration>
<runtime>
<gcAllowVeryLargeObjects enabled="true" />
</runtime>
</configuration>