views:

6528

answers:

6

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;
        }
    }
}
+1  A: 

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.

http://stackoverflow.com/questions/588882/unmanaged-vc-applications-memory-consumption-on-windows-server

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...)

uzbones
Hi uzbones, does it mean 4G memory is useless? My application could only consume maximum 2G?
George2
Well... 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.
uzbones
I 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
Yes, 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 http://en.csharp-online.net/.NET_Architecture%E2%80%94Application_domains
uzbones
Thanks uzbones, very good document!
George2
+13  A: 

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.

JaredPar
The .5GB is can also be everything else running on the machine that isn't O/S components.
Robert C. Barth
No, each process gets a fully adressable 2 GB virtual memory space.
Nick
Nick is correct. Each process's address space is independent of anothers. Unless they choose to dabble in shared memory.
JaredPar
1. Hi JaredPar, 1.5G memory limitation is for per process or per thread?2. Do you have any documents for this limitation? :-)
George2
@George2 it's per process. Link http://msdn.microsoft.com/en-us/library/ms810627.aspx Read down to the section titled "Virtual memory in Win32"
JaredPar
Hi 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?
George2
Swap 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...
Marc Gravell
I 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
@George2 that is correct
JaredPar
In 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.
Leon Breedt
+3  A: 

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.

geofftnz
I 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
Yeah, 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...
geofftnz
Cool, thanks geofftnz!
George2
+3  A: 

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.

KristoferA - Huagati.com
Although 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.
uzbones
I 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
+5  A: 

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)

Marc Gravell
When 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.
JaredPar
1."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
1.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?
George2
I 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
Windows 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.
Marc Gravell
Thanks 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"
George2
It 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
http://msdn.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
Marc Gravell
The 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.
Marc Gravell
Hi Marc, I read the document about "Array Size Limitations" you recommended. But I disagree it comments "In the 64-bit runtime, pointers are 8 bytes, which cuts the maximum size of your array in half, to 268,435,447 items." -- I think on 64-bit there should be no such limitaiton? Any comments?
George2
I 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?
George2
Any 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
Re 2GB: both 32 and 64 impose a 2GB-per-single-object limitation. But you can have multiple arrays to have bigger sets of data.
Marc Gravell
+1  A: 

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.

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.

Yort