实验环境: 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;
}