/* Usage: memalloc.exe >log.txt
 * 
 * This program prints to standard output a list of the current
 * allocation of memory blocks (address space), as understood by
 * the Windows API function VirtualQuery.
 *
 * Typical use is to identify ill-behaved dll's that allocate
 * small amounts of memory in the middle of an application's
 * address space, thus preventing the allocation of large blocks
 * of memory even though plenty of memory is available in the aggregate.
 *
 * It is a Good Thing if the largest MEM_FREE region reported by
 * this program is on the order of 1.5 GB.  (The maximum process
 * size allowed by Windows is 2 GB.)
 *
 * Known to compile with mingw gcc with -static command line option,
 * in which case largest MEM_FREE region of slightly over
 * 2 * 10^9 bytes is observed.
 *
 * Rik Littlefield, 7/1/2004.
 *
 */

#include <windows.h>
#include <stdio.h>

main (int argc, char* argv[]) {
	
	DWORD  largestBlock = 0;
	
    MEMORY_BASIC_INFORMATION mbi;
    DWORD      dwMemUsed = 0;
    PVOID      pvAddress = 0;
    CHAR      szBuf[512];
    
    memset(&mbi, 0, sizeof(MEMORY_BASIC_INFORMATION));

    while(pvAddress < (PVOID)0x80000000 && 
          VirtualQuery(pvAddress, &mbi, sizeof(MEMORY_BASIC_INFORMATION)) 
             == sizeof(MEMORY_BASIC_INFORMATION)) {
		szBuf[0] = 0;
        GetModuleFileNameA((HINSTANCE)mbi.AllocationBase, szBuf, 512);
        printf("Address %x, length %x, state %x",pvAddress,mbi.RegionSize,mbi.State);
        if (mbi.State == MEM_COMMIT) printf(" MEM_COMMIT");
        if (mbi.State == MEM_FREE) printf(" MEM_FREE");
        if (mbi.State == MEM_RESERVE) printf(" MEM_RESERVE");
        printf(", type %x", mbi.Type);
        if (mbi.State == MEM_PRIVATE) printf(" MEM_PRIVATE");
        if (mbi.State == MEM_IMAGE) printf(" MEM_IMAGE");
        if (mbi.State == MEM_MAPPED) printf(" MEM_MAPPED");
        printf(" module %s",szBuf);
        printf("\n");
        if (mbi.State == MEM_FREE && mbi.RegionSize > largestBlock) {
			largestBlock = mbi.RegionSize;
		}
        pvAddress = ((BYTE*)mbi.BaseAddress) + mbi.RegionSize;
    }
        
    printf("Largest MEM_FREE region = %x (%d)\n",largestBlock,largestBlock);
}

