Reputation: 21
I have a .NET application that is running out of memory only when I run it in x86 on windows 7 mode with the following exception
8/4/2013 11:36:52 AM: Main application context(1) CriticalError: Exception in Application context Run: Main application context : Parameter is not valid. at System.Drawing.Image.get_Width()
at System.Drawing.Image.get_Size()
at DevExpress.XtraBars.BarItem.IsSameSize(Image old, Image newImage)
at DevExpress.XtraBars.BarItem.set_Glyph(Image value)
at NordicIT.Mark5.Module.DM.Editor.frmEditorRibbon..ctor()
at NordicIT.Mark5.Module.DM.Editor.frmEditorRibbon..ctor(IEditFormForBOOptions editFormForBOOptions)
at NordicIT.Mark5.Module.DM.Actions.TDMActions.<>c__DisplayClass19.<_DocumentTransmitProcess>b__17()
at System.Windows.Threading.ExceptionWrapper.InternalRealCall(Delegate callback, Object args, Int32 numArgs)
The memory consumption is around 400 mb, GDI Objects consumed around 1500(I have increased the limit of these in the registry so should not be any problem to go to around 10000 ).
When I run the same application in Windows server 2008 R2 in x86 i have no problem(it should have the same kernel as windows 7), in windows xp in x86 also no problem.
I never have an exception in x64 mode even if I go with the memory up to 2 gb.
Please help me to understand which limitation in terms of memory I am reaching.
Upvotes: 2
Views: 1423
Reputation: 941505
GDI+ exceptions are rather poor, caused by it being developed long before .NET came around and having just a few error codes. In a case like this, it is actually quite likely that memory is the problem. "Parameter is not valid" is GDI+ punting at the reason why the image can't be loaded. Which could be because the image file contains junk, which in turn would get it to try to allocate too much memory. Poor choice in the vast number of cases.
A 32-bit process has 2 gigabytes of virtual memory, regardless of how much RAM your machine has. The address space needs to be shared by code and data. Chunks of it will be occupied by the CLR, the jitter, the framework assemblies, your assemblies, the jitted code for your program and the roughly 10 distinct heaps that a .NET program uses, including the GC heaps. The allocations for these chunks tend to be scattered through the address space. When you allocate memory then you'll grab another chunk from the available holes between these existing chunks.
A big problem with bitmaps is that they can be quite large. And they need to fit inside an available hole. These holes tend to become smaller over time as the program allocates and releases memory. A problem called "address space fragmentation". You can typically find a ~650 megabyte hole when your program first starts. But that rapidly goes down from there when your program has been running for a while. The danger zone for a long-running program is around ~90 megabytes, give or take.
Your program bombs with this exception when there isn't a hole available that's large enough to fit the bitmap. This will happen long before your program has consumed all available virtual memory. You can make many small allocations but not one large one.
There is a simple fix for this problem. Change the Target platform setting on your EXE project to AnyCPU, turn off "Prefer 32-bit" for VS2012 and up. On a 64-bit operating system, a program has a much bigger VM address space, a terabyte is possible. You can't run out of big enough holes.
Upvotes: 9