Why am I getting an Out Of Memory Exception in my C# application?
Solution 1
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.
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.
Update: in .Net 4.5 in 64 bit process you can have large arrays if gcAllowVeryLargeObjects setting is enabled:
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.
<configuration>
<runtime>
<gcAllowVeryLargeObjects enabled="true" />
</runtime>
</configuration>
Solution 2
Just additional to the other points; if you want access to a dirty amount of memory, consider x64 - but be aware that the maximum single object size is still 2GB. And because references are larger in x64, this means that you actually get a smaller maximum array/list size for reference-types. Of course, by the time you hit that limit you are probably doing things wrong anyway!
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 gcAllowVeryLargeObjects is enabled. Note that the limit for string
is not affected, but "arrays" should cover "lists" too, since lists are backed by arrays.
Solution 3
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.
Solution 4
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.
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.
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.
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:
<configuration>
<runtime>
<gcAllowVeryLargeObjects enabled="true" />
</runtime>
</configuration>
Solution 5
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.
George2
Updated on March 12, 2020Comments
-
George2 over 4 years
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)?
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; } } }
-
Robert C. Barth over 15 yearsThe .5GB is can also be everything else running on the machine that isn't O/S components.
-
Nick over 15 yearsNo, each process gets a fully adressable 2 GB virtual memory space.
-
JaredPar over 15 yearsNick is correct. Each process's address space is independent of anothers. Unless they choose to dabble in shared memory.
-
uzbones over 15 yearsAlthough to use the /3Gb switch you will have to modify the executable to manually set a flag in it for it to be able to take advantage of the boot flag.
-
George2 over 15 years1. Hi JaredPar, 1.5G memory limitation is for per process or per thread? 2. Do you have any documents for this limitation? :-)
-
George2 over 15 yearsHi uzbones, does it mean 4G memory is useless? My application could only consume maximum 2G?
-
JaredPar over 15 years@George2 it's per process. Link msdn.microsoft.com/en-us/library/ms810627.aspx Read down to the section titled "Virtual memory in Win32"
-
George2 over 15 yearsHi JaredPar, but how much we could use from user mode? I think we should be able to use more than 2G since Windows should use swap page file. Any comments?
-
Marc Gravell over 15 yearsSwap file is irrelevant; you can only address 2GB... well, unless you use the 3GB switch on a server and mark the exe large address aware...
-
JaredPar over 15 yearsWhen you say max single object are you talking about CLR objects or raw allocation size (native or managed). I assume the former but wanted to check. Also do you have a reference for this, I hadn't seen that yet. Can't imagine why you would want to exceed 2GB though for a single object.
-
George2 over 15 years1. "be aware that the maximum single object size is still 2GB" -- Marc, do you have documents to prove this statement? I am especially interested in what means single object, as we can composite objects to form new objects, so what means single object in your context?
-
George2 over 15 years1. How do you get the conclusion -- "this means that you actually get a smaller maximum array/list size for reference-types." from "because references are larger in x64"? Could you provide more details please?
-
uzbones over 15 yearsWell... no, by having more than 4G of memory, you could run two copies of you program each consuming 2G of memory each. And as KristoferA mentions further below there is a system switch that can be done to change the amount to 3G, or you need to go 64-bit.
-
George2 over 15 yearsI have made more study by myself. I the the reason why there is limitation in 32-bit system is because application access memory by using virtual address, even if we could have more than 4G physical memory, but the actual root limitaiton virtual memory address space, correct?
-
George2 over 15 yearsI have made more study by myself. I the the reason why there is limitation in 32-bit system is because application access memory by using virtual address, even if we could have more than 4G physical memory, but the actual root limitaiton virtual memory address space, correct?
-
George2 over 15 yearsI have made more study by myself. I the the reason why there is limitation in 32-bit system is because application access memory by using virtual address, even if we could have more than 4G physical memory, but the actual root limitaiton virtual memory address space, correct?
-
George2 over 15 yearsI have made more study by myself. I the the reason why there is limitation in 32-bit system is because application access memory by using virtual address, even if we could have more than 4G physical memory, but the actual root limitaiton virtual memory address space, correct?
-
George2 over 15 yearsI have made more study by myself. I the the reason why there is limitation in 32-bit system is because application access memory by using virtual address, even if we could have more than 4G physical memory, but the actual root limitaiton virtual memory address space, correct?
-
Marc Gravell over 15 yearsWindows itself imposes the 2gb/3gb limit per process on win32. The theoretical limit with 32-bit references is 4gb. Win64 blows both of these limitations out of the water.
-
George2 over 15 yearsThanks Marc! Is my understanding correct? -- "I the the reason why there is limitation in 32-bit system is because application access memory by using virtual address, even if we could have more than 4G physical memory, but the actual root limitaiton virtual memory address space"
-
Marc Gravell over 15 yearsIt depends whether by "virtual memory" you mean the virtualized memory model within a process, or whether you mean the "swap" data. It is it the first.
-
Marc Gravell over 15 yearsmsdn.microsoft.com/en-us/library/ms241064(VS.80).aspx "As with 32-bit Windows operating systems, there is a 2GB limit on the size of an object you can create while running a 64-bit managed application on a 64-bit Windows operating system.". The array itself counts as a single object.
-
Marc Gravell over 15 yearsNote that in the case of ref-types (classes), the array only holds the references. In x86, a pointer/reference is 4 bytes; in x64 it is 8 bytes. Thus you get half as many references in the maximum array: informit.com/guides/content.aspx?g=dotnet&seqNum=659
-
Marc Gravell over 15 yearsThe other option is a jagged array; unlike a rectangular array, this composes an array of arrays (or list of lists, etc), giving you a much larger count of references, simply by not having a single huge object, but lots of fairly large objects.
-
uzbones over 15 yearsYes, in a 32bit system in order to access more than 4G of memory (2G user-mode and 2G system) the operating system would need to use something bigger than a 32-bit int for an index. You can get around this by using AppDomains en.csharp-online.net/…
-
geofftnz over 15 yearsYeah, pretty much. All your pointers are stored in 4 bytes, which sets a limit of how much they can see. Things were even worse back in the days of 16-bit pointers. Dont ask me about segment:offset or windowing high memory...
-
George2 over 15 yearsI read "As with 32-bit Windows operating systems, there is a 2GB limit on the size of an object you can create while running a 64-bit managed application on a 64-bit Windows operating system." -- but very confused. It is 2G limit on 32-bit or on 64-bit?
-
Marc Gravell over 15 yearsAny comments?: regardless, there is this limitation. I'm not sure that I can find a good reason to chanllenge this limitation; there are other ways (jagged etc) of getting bit sets of data without needint a single contiguous block.
-
Marc Gravell over 15 yearsRe 2GB: both 32 and 64 impose a 2GB-per-single-object limitation. But you can have multiple arrays to have bigger sets of data.
-
Leon Breedt over 14 yearsIn addition, if you do interop with native code that does lots of small allocations, you may encounter OutOfMemoryException as well when you get back to .NET and the CLR tries to allocate a contiguous chunk (I believe LOH chunk size is between 16MB and 64MB, but I think that varies) to expand the heap. This is much less likely to occur on 64-bit though due to increased address space.
-
Alexei Levenkov over 10 yearsI've added
gcAllowVeryLargeObject
comment as this is top accepted question (+1 to Marc Gravell answer too since it already contains this information). -
ilasno about 9 years+1 for the Visual Studio build properties - this allowed my application to use a little over 4GB that it needed.