I have a Visual Studio 2008 C++ application for Windows Mobile 6.x where I'm counting the amount of free virtual memory available for a given process. (I realize it is not taking fragmentation in to account.) My code looks basically like this:
MEMORY_BASIC_INFORMATION mbi = { 0 };
/// total free memory available to the process
DWORD free = 0;
/// base memory address for the given process index (2-33).
DWORD slot_base_addr = process_index * 0x02000000;
/// look at each memory region for the process.
for( DWORD offset = 0x10000;
offset < 0x02000000;
offset += mbi.RegionSize )
{
::VirtualQuery( ( void* )( slot_base_addr + offset ),
&mbi,
sizeof( MEMORY_BASIC_INFORMATION ) );
if( mbi.State == MEM_FREE )
{
free += ( mbi.RegionSize - ( ( ~( DWORD )mbi.BaseAddress + 1 ) & 0xffff ) ) & 0xffff0000;
}
}
NKDbgPrintfW( L"%d bytes free\r\n", free );
I can confirm with other APIs that this seems to work perfectly. My question is what this line is doing:
free += ( mbi.RegionSize - ( ( ~( DWORD )mbi.BaseAddress + 1 ) & 0xffff ) ) & 0xffff0000;
Why is this not just:
free += mbi.RegionSize;
I found the former line on a Usenet post by MSFT employee Ross Jordan.
Thanks, PaulH
Edit:
For example. For process slot 2, this is a list of each free memory block with the amount of free memory given by both the Ross Jordan (RS) algorithm and just the RegionSize (RS).
Slot: 2. Range: 0x04000000 - 0x06000000
RS: 16,384 bytes RJ: 0 bytes diff: 16384
RS: 4,096 bytes RJ: 0 bytes diff: 4096
RS: 4,096 bytes RJ: 0 bytes diff: 4096
RS: 4,096 bytes RJ: 0 bytes diff: 4096
RS: 4,096 bytes RJ: 0 bytes diff: 4096
RS: 4,096 bytes RJ: 0 bytes diff: 4096
RS: 36,864 bytes RJ: 0 bytes diff: 36864
RS: 65,536 bytes RJ: 65,536 bytes diff: 0
RS: 53,248 bytes RJ: 0 bytes diff: 53248
RS: 4,096 bytes RJ: 0 bytes diff: 4096
RS: 4,096 bytes RJ: 0 bytes diff: 4096
RS: 4,096 bytes RJ: 0 bytes diff: 4096
RS: 4,096 bytes RJ: 0 bytes diff: 4096
RS: 4,096 bytes RJ: 0 bytes diff: 4096
RS: 7,671,808 bytes RJ: 7,667,712 bytes diff: 4096
RS: 1,921,024 bytes RJ: 1,900,544 bytes diff: 20480
RS: 7,491,584 bytes RJ: 7,471,104 bytes diff: 20480
RS: 3,252,224 bytes RJ: 3,211,264 bytes diff: 40960
RS: 262,144 bytes RJ: 262,144 bytes diff: 0
RS: Total VM Free: 20,811,776 bytes.
RJ: Total VM Free: 20,578,304 bytes.
Edit 2:
Hans led me to the answer. It's just a fancy way of doing this, but assuming that the allocation size is 64KB.
SYSTEM_INFO si = { 0 };
::GetSystemInfo( &si );
free += mbi.RegionSize - mbi.RegionSize % si.dwAllocationGranularity;
Allocation granularity for VirtualAlloc is normally 64KB. He tries to do something meaningful if the AllocationBase is not a multiple of 64KB. I don't think it is meaningful at all, his bitmasks still assume a granularity of 64KB and he doesn't use SYSTEM_INFO.dwAllocationGranularity. Which has this comment:
This value was hard coded as 64 KB in the past, but other hardware architectures may require different values.
In the very rare case where it is not 64KB, this code would generate junk values. Just zap it, go by RegionSize.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With