实验环境: Win7X64Sp1 + vs2008, 物理内存16GB.
实验结论:
* 进程堆的最大Size并没有使用完剩余的物理内存
* 每次能分配的最大堆空间接近2M, 不管是私有堆,还是进程堆, 和堆初始Size无关,
* 将堆空间用尽后, 累计堆空间总Size接近2000MB, 不管是私有堆,还是进程堆, 和堆初始Size无关,
/// @file getHeapSize.cpp /// @brief 尝试得到本进程堆的最大size #include "stdafx.h" #include <Windows.h> #include <tchar.h> #define MEMORY_REQUESTED_MB (1024 * 1024) ///< 请求的堆尺寸单位(MB) size_t GetSystemPageSize(); bool GetHeapSize(HANDLE hHeap, size_t & nSizeHeapOnce, size_t & nSizeHeap); bool GetHeapAllocTotal(HANDLE hHeap, size_t nSizeHeapOnce, size_t & nSizeHeapTotal); ///< 计算在堆上能分配的空间总和 int _tmain(int argc, _TCHAR* argv[]) { bool bRc = false; int iIndex = 0; size_t nSizeHeap = 0; size_t nSizeHeapOnce = 0; size_t nSizeHeapTotal = 0; HANDLE hHeap = GetProcessHeap(); _tprintf(L"when hHeap = GetProcessHeap();\n"); for(iIndex = 0; iIndex < 5; iIndex++) { bRc = GetHeapSize(hHeap, nSizeHeapOnce, nSizeHeap); _tprintf( L"GetHeapSize() = %s, nSizeHeap = 0x%X, %.3f(MB)\n", bRc ? L"TRUE" : L"FALSE", nSizeHeap, 1.0f * nSizeHeap / MEMORY_REQUESTED_MB); } /// 对私有堆的测试 nSizeHeap = MEMORY_REQUESTED_MB * 10; hHeap = HeapCreate(0, GetSystemPageSize() * 4, nSizeHeap); ///< 建立10MB的私有堆, 每次提交4Page if(NULL == hHeap) _tprintf(L"HeapCreate error code = 0x%x\n", GetLastError()); else { _tprintf(L"HeapCreate Ok, nSizeHeap = %dMB\n", nSizeHeap / MEMORY_REQUESTED_MB); for(iIndex = 0; iIndex < 5; iIndex++) { bRc = GetHeapSize(hHeap, nSizeHeapOnce, nSizeHeap); _tprintf( L"GetHeapSize() = %s, nSizeHeap = 0x%X, %.3f(MB)\n", bRc ? L"TRUE" : L"FALSE", nSizeHeap, 1.0f * nSizeHeap / MEMORY_REQUESTED_MB); } HeapDestroy(hHeap); } /// 测试从私有堆上能分配的最大空间, 依次分配一块, 计算能分配的空间总和 nSizeHeap = MEMORY_REQUESTED_MB * 10; if(0 == nSizeHeapOnce) nSizeHeapOnce = GetSystemPageSize(); _tprintf(L"nSizeHeapOnce = 0x%x\n", nSizeHeapOnce); hHeap = HeapCreate(0, nSizeHeapOnce, nSizeHeap); ///< 建立10MB的私有堆, 每次提交4Page if(NULL == hHeap) _tprintf(L"HeapCreate error code = 0x%x\n", GetLastError()); else { _tprintf(L"HeapCreate Ok, nSizeHeap = %dMB\n", nSizeHeap / MEMORY_REQUESTED_MB); bRc = GetHeapAllocTotal(hHeap, nSizeHeapOnce, nSizeHeapTotal); _tprintf( L"GetHeapAllocTotal() = %s, nSizeHeapOnce = 0x%X, %.3f(MB), nSizeHeapTotal = 0x%X, %.3f(MB)\n", bRc ? L"TRUE" : L"FALSE", nSizeHeapOnce, 1.0f * nSizeHeapOnce / MEMORY_REQUESTED_MB, nSizeHeapTotal, 1.0f * nSizeHeapTotal / MEMORY_REQUESTED_MB); HeapDestroy(hHeap); } /** operating results 将程序编译成Release + win32, 在IDE外直接运行 when hHeap = GetProcessHeap(); GetHeapSize() = TRUE, nSizeHeap = 0x70CBF000, 1804.746(MB) GetHeapSize() = TRUE, nSizeHeap = 0x70CBF000, 1804.746(MB) GetHeapSize() = TRUE, nSizeHeap = 0x70CBF000, 1804.746(MB) GetHeapSize() = TRUE, nSizeHeap = 0x70CBF000, 1804.746(MB) GetHeapSize() = TRUE, nSizeHeap = 0x70CBF000, 1804.746(MB) HeapCreate Ok, nSizeHeap = 10MB GetHeapSize() = TRUE, nSizeHeap = 0x1FF000, 1.996(MB) GetHeapSize() = TRUE, nSizeHeap = 0x1FF000, 1.996(MB) GetHeapSize() = TRUE, nSizeHeap = 0x1FF000, 1.996(MB) GetHeapSize() = TRUE, nSizeHeap = 0x1FF000, 1.996(MB) GetHeapSize() = TRUE, nSizeHeap = 0x1FF000, 1.996(MB) nSizeHeapOnce = 0x1ff000 HeapCreate Ok, nSizeHeap = 10MB GetHeapAllocTotal() = TRUE, nSizeHeapOnce = 0x1FF000, 1.996(MB), nSizeHeapTotal = 0x7C41C000, 1988.109(MB) 剩余物理内存是8655M, 看来进程堆的最大Size并没有使用完剩余的物理内存 经过多次实验, 进程堆的Size大约是1800上下几MB 建立10MB的私有堆, 测试出的私有堆大小为2MB左右?? 建立了20MB的私有堆, 测试出的私有堆大小也为2MB左右. 建立了100MB的私有堆, 测试出的私有堆大小也为2MB左右. 结论: 进程私有堆是程序编译时指定的, 指定多大都没用 在vs2008中设置对大小为10MB, 10485760 设置步骤: vs2008工程属性 >> Configuration Properties >> Linker >> System >> Heap Reserver Size 实验结果: * 每次能分配的堆空间一直2M左右, 不管是私有堆,还是进程堆, 和堆初始Size无关, * 能分配的堆空间总和接近2000MB, 不管是私有堆,还是进程堆, 和堆初始Size无关, */ getchar(); return 0; } bool GetHeapAllocTotal(HANDLE hHeap, size_t nSizeHeapOnce, size_t & nSizeHeapTotal) { bool bRc = false; BYTE * pBufHeap = NULL; nSizeHeapTotal = 0; do { pBufHeap = static_cast<BYTE *>(HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, nSizeHeapOnce)); if(NULL != pBufHeap) { bRc = true; nSizeHeapTotal += nSizeHeapOnce; } } while (NULL != pBufHeap); return bRc; } bool GetHeapSize(HANDLE hHeap, size_t & nSizeHeapOnce, size_t & nSizeHeap) { bool bRc = false; size_t nSystemPageSize = GetSystemPageSize(); int iMultiple = 0; ///< 内存申请容量是SYSTEM_INFO.PageSize的倍数 BYTE * pBufHeap = NULL; iMultiple = static_cast<size_t>(MEMORY_REQUESTED_MB) / nSystemPageSize; nSizeHeap = iMultiple * nSystemPageSize; ///< 从1MB开始尝试 do { pBufHeap = static_cast<BYTE *>(HeapAlloc(hHeap, HEAP_ZERO_MEMORY, nSizeHeap)); if(NULL != pBufHeap) { if(FALSE == HeapFree(GetProcessHeap(), 0, pBufHeap)) return false; } iMultiple *= 2; ///< 快速靠近堆上限制 nSizeHeap = iMultiple * nSystemPageSize; } while (NULL != pBufHeap); ///< 一直尝试到失败为止 /// 从失败的最大Size往小申请, 第一次成功的Size就是进程堆的Size nSizeHeap = --iMultiple * nSystemPageSize; do { pBufHeap = static_cast<BYTE *>(HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, nSizeHeap)); if(NULL != pBufHeap) { if(FALSE == HeapFree(GetProcessHeap(), 0, pBufHeap)) { return false; } bRc = true; nSizeHeapOnce = nSizeHeap; break; } nSizeHeap = --iMultiple * nSystemPageSize; } while (NULL == pBufHeap); ///< 一直尝试到成功为止 return bRc; } size_t GetSystemPageSize() { /// SYSTEM_INFO.dwPageSize : 页面大小和页保护和承诺的粒度, 是VirtualAlloc的入参 SYSTEM_INFO sSysInfo; GetSystemInfo(&sSysInfo); return sSysInfo.dwPageSize; }