VirtualQuery的使用
VirtualQuery函数可以查询本进程地址空间中内存区域的详细情况(区域大小,区域内容等信息)
函数原型:DWORD VirtualQuery(LPVOID lpAddress,PMEMORY_BASIC_INFORMATION lpBuffer,DWORD dwLength);
lpAddress:表示要查询状态的内存区域开始地址
lpBuffer:一个用于返回的结构数据的缓冲
dwLength:是缓冲的长度
使用VirtualQueryEx函数可以查询指定进程的地址空间情况,原型:SIZE_T WINAPI VirtualQueryEx(HANDLE hProcess,LPVOID lpAddress,PMEMORY_BASIC_INFORMATION lpBuffer,DWORD dwLength);
hProcess:待查询其地址空间的进程句柄。
用此函数无法查询内核分区情况,只能查询用户分区的内存使用情况。
/************************************************************************/
/*
程序说明:VirtualQuery的使用,通过VirtualQuery输出内存信息
日期 :2014/12/30
*/
/************************************************************************/
#include "stdafx.h"
#include <windows.h>
#include <atlstr.h>
/************************************************************************/
/*
功能:把内存信息结构体信息格式化输出。
参数:mi:内存信息结构体
返回:格式化字符串
*/
/************************************************************************/
CString FormatMemInfo(MEMORY_BASIC_INFORMATION &mi)
{
CString strAllocProtect;
//内存区域初始化时的保护方式
if(mi.AllocationProtect & PAGE_NOACCESS) // 0x0001
{
strAllocProtect = _T("N ");
}
if(mi.AllocationProtect & PAGE_READONLY) // 0x0002
{
strAllocProtect = _T("R ");
}
else if(mi.AllocationProtect & PAGE_READWRITE) // 0x0004
{
strAllocProtect = _T("RW ");
}
else if(mi.AllocationProtect & PAGE_WRITECOPY) // 0x0008
{
strAllocProtect = _T("WC ");
}
else if(mi.AllocationProtect & PAGE_EXECUTE) // 0x0010
{
strAllocProtect = _T("E ");
}
else if(mi.AllocationProtect & PAGE_EXECUTE_READ) // 0x0020
{
strAllocProtect = _T("ER ");
}
else if(mi.AllocationProtect & PAGE_EXECUTE_READWRITE) // 0x0040
{
strAllocProtect = _T("ERW");
}
else if(mi.AllocationProtect & PAGE_EXECUTE_WRITECOPY) // 0x0080
{
strAllocProtect = _T("EWC");
}
if(mi.AllocationProtect & PAGE_GUARD) // 0x0100
{
strAllocProtect += _T("+Guard");
}
if(mi.AllocationProtect & PAGE_NOCACHE) // 0x0200
{
strAllocProtect += _T("+NoCache");
}
//内存页的状态
CString strState;
if(mi.State == MEM_COMMIT)
{
strState = _T("Commit ");
}
else if(mi.State == MEM_FREE)
{
strState = _T("Free ");
}
else if(mi.State == MEM_RESERVE)
{
strState =_T( "Reserve");
}
else
{
strState =_T( "Damned ");
}
//内存页的当前保护属性
CString strProtect;
if(mi.Protect & PAGE_NOACCESS)
{
strProtect = _T("N ");
}
else if(mi.Protect & PAGE_READONLY)
{
strProtect = _T("R ");
}
else if(mi.Protect & PAGE_READWRITE)
{
strProtect = _T("RW ");
}
else if(mi.Protect & PAGE_WRITECOPY)
{
strProtect = _T("WC ");
}
else if(mi.Protect & PAGE_EXECUTE)
{
strProtect = _T("E ");
}
else if(mi.Protect & PAGE_EXECUTE_READ)
{
strProtect = _T("ER ");
}
else if(mi.Protect & PAGE_EXECUTE_READWRITE)
{
strProtect = _T("ERW");
}
else if(mi.Protect & PAGE_EXECUTE_WRITECOPY)
{
strProtect = _T("EWC");
}
else if(mi.Protect & PAGE_GUARD)
{
strProtect += _T("+Guard");
}
else if( mi.Protect & PAGE_NOCACHE )
{
strProtect += _T("+NoCache");
}
//内存页类型
CString strType;
if(mi.Type == MEM_IMAGE)
{
strType =_T( "Image ");
}
else if(mi.Type == MEM_MAPPED)
{
strType = _T("Mapped ");
}
else if(mi.Type == MEM_PRIVATE)
{
strType = _T("Private");
}
else
{
strType = _T("- ");
}
CString strRet;
strRet.Format(_T("%8X %8X %8X %8uKB %5s %7s %5s %7s"), mi.BaseAddress, mi.AllocationBase
, (DWORD)mi.AllocationBase + (DWORD)mi.RegionSize
, (DWORD)mi.RegionSize/1024
, strAllocProtect, strState, strProtect, strType);
return strRet;
}
int _tmain(int argc, _TCHAR* argv[])
{
SYSTEM_INFO info;
//获取系统信息
GetSystemInfo(&info);
//最小的内存地址和最大的内存地址
void * pLowerBound = (void*)info.lpMinimumApplicationAddress;
void * pUpperBound = (void*)info.lpMaximumApplicationAddress;
MEMORY_BASIC_INFORMATION mi;
void* pPtr = pLowerBound;
void* pOldPtr = pPtr;
_putts(_T("BaseAddress AllocBase EndAddress Size AllocProtect State CurProtect TYPE"));
while (pPtr <= pUpperBound)
{
//查询自己进程中的虚拟内存页的信息
if (VirtualQuery(pPtr,&mi,sizeof(mi)) == 0)
{
break;
}
_putts(FormatMemInfo(mi));
pOldPtr = pPtr;
pPtr = (BYTE*)mi.BaseAddress+mi.RegionSize;
if (pPtr <= pOldPtr)
{
break;
}
}
_tsystem(_T("pause"));
return 0;
}
Windows堆管理器的使用:
1 与虚拟内存管理不同,Windows为小块内存的管理提供了Windows堆管理器。
2 Windows堆管理器内部在底层依然调用了虚拟内存管理。
3 Windows堆属于进程,进程内的所有线程都可以访问该进程中所有的堆。
4 Windows为每个进程在准备启动时都默认创建了一个堆,使用GetProcessHeap函数可以得到这个默认堆的句柄。
WIndows堆API的使用:
1 因为堆API与C/C++堆管理方式类同,因此可以使用这组堆API直接代替C/C++的堆管理函数或运算符。
2 windows堆API的性能仅次于虚拟内存管理,但是高于任何其他堆管理函数。
3 因为依托于虚拟内存管理,所以可以使用windows堆函数分配想要的任意尺寸的内存块。
4 使用HeapSize可以快速的得到某块已分配内存的原始分配大小,方便校验和限定对内存的访问。
5 使用HeapValidate可以校验一个对内存的完整性,从而提早发现野指针等问题
6 使用heapWalk可以遍历堆,从而有机会检测到内存泄漏的问题。
代码如下:
/************************************************************************/
/*
程序的使用:堆的使用
日期 :2014/12/30
*/
/************************************************************************/
#include "stdafx.h"
#include <windows.h>
#include <time.h>
int _tmain(int argc, _TCHAR* argv[])
{
srand((unsigned int)time(NULL));
//使用默认堆
HANDLE hHeap = GetProcessHeap();
const int iCnt = 1000;
float* fArray = (float*)HeapAlloc(hHeap,HEAP_ZERO_MEMORY,iCnt * sizeof(float));
for (int i = 0; i < iCnt; i++)
{
fArray[i] = 1.0f * rand();
}
fArray = (float*)HeapReAlloc(hHeap,HEAP_ZERO_MEMORY,fArray,2 * iCnt * sizeof(float));
for (int i = iCnt; i < 2 * iCnt; i++)
{
fArray[i] = 1.0f * rand();
}
HeapFree(hHeap,0,fArray);
//使用私有堆
hHeap = HeapCreate(HEAP_GENERATE_EXCEPTIONS,0,0);
fArray = (float*)HeapAlloc(hHeap,HEAP_ZERO_MEMORY,iCnt * sizeof(float));
for (int i = 0; i < iCnt; i++)
{
fArray[i] = 1.0f * rand();
}
fArray = (float*)HeapReAlloc(hHeap,HEAP_ZERO_MEMORY,fArray,2 * iCnt * sizeof(float));
for (int i = iCnt; i < 2 * iCnt; i++)
{
fArray[i] = 1.0f * rand();
}
HeapFree(hHeap,0,fArray);
HeapDestroy(hHeap);
return 0;
}