views:

745

answers:

6

I have a C# app that must link with a 32-bit library and also needs to use the maximum amount of memory possible (imaging app); we run the app on XP64 desktops, thus we are using WOW64, targeting builds in Visual Studio for x86 (and doing an editbin /largeaddressaware post-build). We're encountering a few problems:

  • In the Visual Studio built-in debugger, we can only ever use 2gb of memory (~1.5gb to the app, plus overhead)

  • Running from the command line, the app can see 3gb of memory, but Microsoft documents would seem to say we should see 4gb.

Can anyone tell me how to get a WOW64 C# app to see the full 4gb that the platform should be able to give it?

Also, can anyone tell me how to get the Visual Studio (VS 2008, otherwise known as VS90) debugger to obey the /largeaddressaware bit and stop limiting the app memory to 2gb?

I see the same behavior in VS80 and VS90; also no difference between .NET Framework 3.5, 3.0, and 2.0. Here's a trivial C# program that illustrates the problems; build for x86, editbin /largeaddressaware, then run in built-in debugger versus run from command line to see the difference in memory available to C#.

namespace MemoryAllocTest
{
class Program
{
    static void Main(string[] args)
    {
        const int allocSize = 1024 * 1024;
        List<byte[]> myMem = new List<byte[]>();
        UInt64 totalAlloc = 0;

        while (true)
        {
            myMem.Add(new byte[allocSize]);
            totalAlloc += allocSize;
            Console.WriteLine("{0} allocs: {1}MB total", 
             myMem.Count, totalAlloc / (1024 * 1024));
        }
    }
}
}
+2  A: 

From Microsoft:

The virtual address space of processes and applications is still limited to 2 GB unless the /3GB switch is used in the Boot.ini file. When the physical RAM in the system exceeds 16 GB and the /3GB switch is used, the operating system will ignore the additional RAM until the /3GB switch is removed. This is because of the increased size of the kernel required to support more Page Table Entries. The assumption is made that the administrator would rather not lose the /3GB functionality silently and automatically; therefore, this requires the administrator to explicitly change this setting. The /3GB switch allocates 3 GB of virtual address space to an application that uses IMAGE_FILE_LARGE_ADDRESS_AWARE in the process header. This switch allows applications to address 1 GB of additional virtual address space above 2 GB.

Dave Swersky
The /3GB switch (known as the 4GT tuning param) is not applicable to 64-bit OS's. See also: http://msdn.microsoft.com/en-us/library/aa366778.aspx
+2  A: 

What exact version of .NET are you using? This Connect report is about the same problem (as far as I can tell), seen on .NET 2.0 but fixed in .NET 2.0SP1.

If your x64 machines don't have 2.0SP1 (or later) on, it's worth a try...

Jon Skeet
Thanks for the pointer -- but no luck! I have 3.5sp1 and all the versions supported/included (2.0, 3.0, 3.5) all show the 3gb behavior.... Drat.
And curiously, the all-important add-on kb fix to 3.5sp1 doesn't apply to XP64.
+1  A: 

Can you post where it implies that you can see all 4 GB? Ooh, maybe here: Interesting info at this link

Differences in Addressable Memory

The first thing most developers notice is that 64-bit processors provide a huge leap in the amount of physical and virtual memory that can be addressed.

* 32-bit applications on 32-bit platforms can address up to 2 GB
* 32-bit applications built with the /LARGEADDRESSAWARE:YES linker flag

on 32-bit Windows XP or Windows Server 2003 with the special /3gb boot option can address up to 3 GB. This constrains the kernel to only 1 GB which may cause some drivers and/or services to fail.

* 32-bit applications built with the /LARGEADDRESSAWARE:YES linker flag

on 32-bit versions of Windows Vista, and on 32-bit versions of Windows Server Code Name "Longhorn" operating systems, can address memory up to the number specified by the boot configuration data (BCD) element IncreaseUserVa. IncreaseUserVa can have a value ranging from 2048, the default, to 3072 (which matches the amount of memory configured by the /3gb boot option on Windows XP). The remainder of 4 GB is allocated to the kernel and can result in failing driver and service configurations.

For more information about BCD, see Boot Configuration Data on MSDN.

* 32-bit applications on 64-bit platforms can address up to 2 GB, or up

to 4 GB with the /LARGEADDRESSAWARE:YES linker flag. * 64-bit applications use 43 bits for addressing, which provides 8 TB of virtual address for applications and 8 TB reserved for the kernel.

So yes, it appears you should (on an XP64 target) be able to see 4 GB.

Joe
+2  A: 

I built your simple sample app from the post, crashed it and attached WinDbg to it.

!address -summary will show you the effective user mode address space for the process.

0:003> !address -summary
 TEB fffdd000 in range fffdb000 fffde000
 TEB fffda000 in range fffd8000 fffdb000
 TEB fffd7000 in range fffd5000 fffd8000
 TEB fffaf000 in range fffad000 fffb0000
 ProcessParametrs 004c2b40 in range 004c0000 00535000
 Environment 004c1978 in range 004c0000 00535000

-------------------- Usage SUMMARY --------------------------
    TotSize (      KB)   Pct(Tots) Pct(Busy)   Usage
   e7d2e000 ( 3798200) : 90.56%    98.77%    : RegionUsageIsVAD
   1547b000 (  348652) : 08.31%    00.00%    : RegionUsageFree
    2887000 (   41500) : 00.99%    01.08%    : RegionUsageImage
     3ff000 (    4092) : 00.10%    00.11%    : RegionUsageStack
          0 (       0) : 00.00%    00.00%    : RegionUsageTeb
     1c0000 (    1792) : 00.04%    00.05%    : RegionUsageHeap
          0 (       0) : 00.00%    00.00%    : RegionUsagePageHeap
       1000 (       4) : 00.00%    00.00%    : RegionUsagePeb
          0 (       0) : 00.00%    00.00%    : RegionUsageProcessParametrs
          0 (       0) : 00.00%    00.00%    : RegionUsageEnvironmentBlock
       **Tot: ffff0000 (4194240 KB)** Busy: eab75000 (3845588 KB)

-------------------- Type SUMMARY --------------------------
    TotSize (      KB)   Pct(Tots)  Usage
   1547b000 (  348652) : 08.31%   : <free>
    2aa3000 (   43660) : 01.04%   : MEM_IMAGE
    1f6a000 (   32168) : 00.77%   : MEM_MAPPED
   e6168000 ( 3769760) : 89.88%   : MEM_PRIVATE

-------------------- State SUMMARY --------------------------
    TotSize (      KB)   Pct(Tots)  Usage
   db838000 ( 3596512) : 85.75%   : MEM_COMMIT
   1547b000 (  348652) : 08.31%   : MEM_FREE
    f33d000 (  249076) : 05.94%   : MEM_RESERVE

Largest free region: Base fbfc0000 - Size 03fed000 (65460 KB)

Based on Tot: ffff0000 (4194240 KB) we do have 4GB of effective user mode space.

Also our largest free block is 65,460KB which does imply that we should be able to allocate more memory.

Jack Bolding
+3  A: 

can anyone tell me how to get the Visual Studio (VS 2008, otherwise known as VS90) debugger to obey the /largeaddressaware bit and stop limiting the app memory to 2gb?

This requires two steps -- both in the project properties:

  • on the build events tab, setup a postbuild step to run editbin /largeaware $(TargetPath)
  • on the debug tab, un-check the Enable the Visual Studio hosting process

With these two steps, your sample program was running to 3045MB

Dave Ganger
Dave, thanks for this -- unchecking the 'enable visual studio hosting process' did indeed get the app to 3gb. But how to go the final distance to 4gb?!Thanks again!
+2  A: 

Thanks to everyone who responded; this site really rocks!

Seems that we really do get to 4gb user space in WOW64, but it seems to me (mildly educated guess) that the garbage collector overhead (or perhaps safety margin) becomes sizeable as the memory allocated by managed code grows. Running my test app on WOW64 (command line, with LARGEADDRESSAWARE), I get total allocations of 3175MB; running on a WIN32 XP machine with the 4GT parameter set, I get total allocations of 2857MB: so a full gig of additional user-mode memory yields an increase of only ~318MB at the C# app level!

(I have modified my test program to halve the allocation unit size when an allocation fails, and also added calls to strategically force garbage collection in an effort to go a little beyond the limit of what a 'normal' application might be able to grab -- drop a note here if you would like me to post the revised code.)

Anyway, thanks again to everyone; looks like the system is working correctly but the managed environment gets less improvement from the additional gig of memory than may have been expected.

As a final note, I'll mention that when I remove the LARGEADDRESSAWARE bit, I get total allocations of 1.9GB on both WOW64 and XP32. So curiously, moving from 2GB user memory to 3GB user memory yields the full benefit to the C# application level, yet the move from 3GB user memory to the 4GB user memory (WOW64 environment) only yields the C# application level a benefit of ~320MB....