Windows虚拟内存的使用(五)

本文介绍了Windows虚拟内存管理中的VirtualQuery函数及其使用,用于查询进程地址空间详情。同时探讨了Windows堆管理器,强调其在进程中的作用,以及与虚拟内存管理的关系。讨论了Windows堆API的优势,如性能、内存大小分配灵活性,并提到了用于检测内存问题的HeapSize、HeapValidate和HeapWalk函数。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >



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;
}




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值