native 64 bit processes get a huge address space of 8 TB (instead of the usual 2GB of 32 bit processes). However, to actually get this address space range, the executable image must be linked with the LARGEADDRESSAWARE flag. If it's not, only the lower 2GB will be available. Why is that? Why doesn't a native 64 bit process get automatically the larger address space? I'll leave you to think about this a bit - I'll answer in a few paragraphs.
int _tmain(int argc, _TCHAR* argv[]) {
void* p;
__int64 total = 0;
SIZE_T chunk = 1 << 28; // 256MB
do {
p = ::VirtualAlloc(NULL, chunk, MEM_COMMIT,
PAGE_READWRITE);
if(p)
printf("Allocated: %p (total=%15I64X)\n",
p, total += chunk);
else
printf("Failed... %d\n", GetLastError());
} while(p);
return 0;
}
The LARGEADRESSAWARE flag can be enabled / disabled by using Project->Properties in Visual Studio and selecting Link->System:
Here are the results when the flag is off:
Notice how the addresses don't go higher than 2GB. Now with the flag enabled:
I can allocate more memory, only limited by the page files size(s).
What's is the default setting? In an x64 project, it's enabled (usually a good thing). In an x86 project, it's disabled (usually not a good thing, I'll explain why).
So, why is that? Why doesn't a process benefit automatically from the larger address space?
For 64 bit processes, the answer lies in porting. A 64 bit app is probably ported from its 32 bit equivalent (maybe even developed side by side). If a dangerous cast exists in the 32 bit application (e.g. casting a void* to an int), this cast will not cause trouble in the 64 bit port - the high DWORD of the pointer will always be zero, so can simply be cut off.
The more interesting question is why not get a 4GB address space that a 32-bit pointer can hold? And while we're at it, on a 32 bit system, the LARGEADDRESSAWARE flag can give a process a 3GB address space (instead of 2GB) if the system has been configured to use it (the /3GB flag in boot.ini in pre-Vista systems, or the equivalent switch to bcdedit in Vista+ systems), but the 3GB space will not be granted unless the app is linked with that flag enabled. Why?
The answer is, that programmers can be too ingenious for their own good. if a programmer knows she can never get a pointer larger or equal to 2GB, she can use the most significant bit (MSB) for some app-specific purpose (a terrible idea, but nothing can stop her). So, if that app suddenly gets a pointer in the range of 2GB-3GB, the MSB will be ruined and so will the app.
To conclude, an app must explicitly state that it understands addresses above 2GB correctly, whether 64 bit or 32 bit.
By the way, a 32 bit app linked with this flag enabled gets a "full" 4GB address space when run on a 64 bit system (the so called "Wow64"). Definitely a bonus!