David Findlay

Breaking the 32MB barrier on Windows (pre-6) CE

In Windows CE 5 and earlier, each process is limited to 32MB of virtual address space. That 32MB has to hold your executable, your DLLs, everyone else's DLLs, your heap, and some other stuff. If you're on a plain Windows CE device the so-called 'DLL crunch' isn't always too bad, since the OEM only has to include what they want or need to include in the platform image. However, on a Windows Mobile device, the OEM has to include everything required to get LTK verification: Pocket Word, and all that fun stuff. That means a bunch of extra DLLs that eat into the available space in your process' slot.

In Windows CE 6, the limit was raised to 2GB, so you have much more breathing room (you are limited to 512MB of physical RAM, but still, what luxury).

So, what do you do if you're developing for pre-6 Windows CE and you run out of heap space for your application? Well, you can play some tricks with DLL load ordering, but that only gets you so far. One neat trick I rely on is what I like to call the 'LMA incantation'. It goes like this:
If you ask for at least 2MB, and you ask for it in a particular way, then CE will allocate that memory for you from the Large Memory Area. This is the area of memory above where the individual 32MB slots exist for normal processes. It's normally used for memory-mapped files (which is another way you can make use of the LMA if you need to).

Here's the incantation:

DWORD size = 2*1024*1024; // (or more)

void *p = VirtualAlloc(0, size, MEM_RESERVE, PAGE_NOACCESS);
p = VirtualAlloc(p, size, MEM_COMMIT, PAGE_READWRITE);

// optional:
#define LMA_START_ADDRESS (0x42000000)
assert(ptr > LMA_START_ADDRESS)


Now if you do this in one line rather than two, that is do the commit without the reserve, then you will get memory from your process' 32MB slot rather than the LMA, and the assert will of course fail.

This one has saved my behind on more than one project. Enjoy!

Notes:
  • From the MSDN description of VirtualAlloc:

    In Windows CE 5.01 and earlier versions, if you call VirtualAlloc with dwSize >= 2 MB, flAllocationType set to MEM_RESERVE, and flProtect set to PAGE_NOACCESS, it automatically reserves memory at the shared memory region. This preserves per-process virtual memory.... Since CE 6.0, irrespective of the value of dwSize, kernel will always try to allocate VM in user process space. Also, user applications cannot call VirtualAlloc with shared heap address range (0x70000000 - 0x7fffffff) since this is read only for user applications and read/write for kernel mode threads.

  • A recent article from CE whiz Doug Boling on CE memory architecture.