虚拟内存分配示例程序VMAlloc

#include<windows.h>
#include<tchar.h>
#include<windowsx.h>
#include"resource.h"
#include<strsafe.h>
/*
	自定义结构和全局宏
*/
typedef struct
{
	BOOL bInUse;
	BYTE bOtherData[2048 - sizeof(BOOL)];
}SOMEDATA,*PSOMEDATA;
//判断一个数是否在一个范围
#define chINRANGE(low, Num, High) (((low) <= (Num)) && ((Num) <= (High)))
#define MAX_SOMEDATA  (50)
/*
	函数前置声明
*/
BOOL Dlg_OnInitDialog(HWND hwnd, HWND hwndFocus, LPARAM lParam);
INT_PTR WINAPI DlgProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
void Cls_OnSize(HWND hwnd, UINT state, int cx, int cy);
VOID GarbageCollect(PVOID pvBase, DWORD dwNum, DWORD dwStructSize);
void Cls_OnDestroy(HWND hwnd);
void Cls_OnCommand(HWND hwnd, int id, HWND hwndCtl, UINT codeNotify);
void Cls_OnPaint(HWND hwnd);
/*
	全局变量
*/
//页面大小
UINT g_uPageSize = 0;
RECT g_rcMemMap;
PSOMEDATA g_pSomeData = NULL;

/*
	主函数
*/
int WINAPI _tWinMain(HINSTANCE hInstance, HINSTANCE, PTSTR szCmdLine, int iCmdShow)
{
	//得到基于CPU的页大小
	SYSTEM_INFO si;
	GetSystemInfo(&si);
	g_uPageSize = si.dwPageSize;
	DialogBoxParam(hInstance, MAKEINTRESOURCE(IDD_DIALOG1), NULL, DlgProc, NULL);
	return 0;
}
/*
	窗口函数
*/
INT_PTR WINAPI DlgProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
	switch (uMsg)
	{
		HANDLE_MSG(hWnd, WM_INITDIALOG, Dlg_OnInitDialog);
		HANDLE_MSG(hWnd, WM_COMMAND, Cls_OnCommand);
		HANDLE_MSG(hWnd, WM_SIZE, Cls_OnSize);
		HANDLE_MSG(hWnd, WM_PAINT, Cls_OnPaint);
		HANDLE_MSG(hWnd, WM_DESTROY, Cls_OnDestroy);
		break;
	}
	return 0;
}

/*-------------------------------------------------------------*/
/*  DlgProc - 对话窗口初始化                                  */
/*-------------------------------------------------------------*/
BOOL Dlg_OnInitDialog(HWND hwnd, HWND hwndFocus, LPARAM lParam)
{
	EnableWindow(GetDlgItem(hwnd, IDC_Index), FALSE);
	EnableWindow(GetDlgItem(hwnd, IDC_Index_Text), FALSE);
	EnableWindow(GetDlgItem(hwnd, IDC_Use), FALSE);
	EnableWindow(GetDlgItem(hwnd, IDC_Clear), FALSE);
	EnableWindow(GetDlgItem(hwnd, IDC_GarbageCollect), FALSE);
	
	//得到内存映射展示的屏幕坐标
	GetWindowRect(GetDlgItem(hwnd, IDC_MEMMAP), &g_rcMemMap);
	/*
	MapWindowPoints的百度解释:
	函数功能:该函数把相对于一个窗口的坐标空间的一组点映射成相对于另一窗口的坐标空 的一组点。

  函数原型:int MapWindowPoints(HWND hWndFrom, HWND hWndTo,LPPOINT lpPoints, UINT cPoints);

  参数:

  hWndfrom:转换点所在窗口的句柄,如果此参数为NULL或HWND_DESETOP则假定这些点在屏幕坐标上。

  hWndTo:转换到的窗口的句柄,如果此参数为NULL或HWND_DESKTOP,这些点被转换为屏幕坐标。

  lpPoints:指向POINT结构数组的指针,此结构数组包含要转换的点,此参数也可指向RECT结构,在此情况下,Cpoints参数应设置为2。

  cPoints:指定LpPoints参数指向的数组中POINT结构的数目。

  返回值:如果函数调用成功,返回值的低位字是每一个源点的水平坐标的像素数目,以便计算每个目标点的水平坐标;高位字是每一个源点的垂直坐标的像素的数目,以便计算每个目标点的垂直坐标,如果函数调用失败,返回值为零。
	*/
	//把得到的屏幕坐标转换为窗口坐标,并把窗口坐标储存在g_rcMemMap中,为了让后面InvalidateRect使用
	MapWindowPoints(NULL, hwnd, (LPPOINT)&g_rcMemMap, 2);
	//销毁表示内存映射位置的窗口
	DestroyWindow(GetDlgItem(hwnd,IDC_MEMMAP));
	//
	TCHAR szBuf[10];
	StringCchPrintf(szBuf, _countof(szBuf), TEXT("%d KB"), g_uPageSize/1024);
	SetDlgItemText(hwnd, IDC_PageSize, szBuf);
	//初始化编辑控件
	SetDlgItemInt(hwnd, IDC_Index, 0, FALSE);
	return TRUE;
}

/*
	窗口改变大小的时候函数
*/
void Cls_OnSize(HWND hwnd, UINT state, int cx, int cy)
{
	
}
/*
	Paint函数,更新内存映射
*/
void Cls_OnPaint(HWND hwnd)
{
	PAINTSTRUCT ps;
	BeginPaint(hwnd, &ps);
	UINT uMaxPage = (MAX_SOMEDATA * sizeof SOMEDATA) / g_uPageSize;
	UINT uMemMapWidth = g_rcMemMap.right - g_rcMemMap.left;
	if (g_pSomeData == NULL)
	{
		//内存还没被预定,画个矩形   g_rcMemMap.right-uMemMapWidth%uMaxPage是去掉没法用表示的那部分
		Rectangle(ps.hdc, g_rcMemMap.left, g_rcMemMap.top,g_rcMemMap.right-uMemMapWidth%uMaxPage,g_rcMemMap.bottom);
	}
	else
	{
		//遍历虚拟地址空间,画出内存映射
		for (UINT uPage = 0; uPage < uMaxPage; uPage++)
		{
			UINT uIndex = uPage * g_uPageSize / sizeof SOMEDATA;
			UINT uIndexLast = uIndex + g_uPageSize / sizeof SOMEDATA;//该页的最后一个索引加1,也就是下一个页面第一个索引
			for (; uIndex < uIndexLast; uIndex++)
			{
				MEMORY_BASIC_INFORMATION mbi;
				VirtualQuery(&g_pSomeData[uIndex], &mbi, sizeof mbi);
				int nBrush = 0;
				switch (mbi.State)
				{
				case MEM_FREE:
					nBrush = WHITE_BRUSH;
					break;
				case MEM_RESERVE:
					nBrush = GRAY_BRUSH;
					break;
				case MEM_COMMIT:
					nBrush = BLACK_BRUSH;
					break;
				}
				//把nBrush载入到设备描述表
				SelectObject(ps.hdc, GetStockObject(nBrush));
				Rectangle(ps.hdc,
					g_rcMemMap.left + uMemMapWidth / uMaxPage * uPage,
					g_rcMemMap.top,
					g_rcMemMap.left + uMemMapWidth / uMaxPage * (uPage + 1),
					g_rcMemMap.bottom
				);
			}
		}
	}
	EndPaint(hwnd, &ps);
}
/*
	销毁函数
*/
void Cls_OnDestroy(HWND hwnd)
{
	if (g_pSomeData != NULL)
		//释放g_pSomeData区域的所有内存
		VirtualFree(g_pSomeData, 0, MEM_RELEASE);
}
/*
	窗口命令
*/
void Cls_OnCommand(HWND hwnd, int id, HWND hwndCtl, UINT codeNotify)
{
	UINT uIndex = 0;
	switch (id)
	{
	case IDCANCEL:
		EndDialog(hwnd, id);
		break;
	case IDC_Reserve:
		//预定虚拟内存空间   得到足够的地址控件去装结构数组,该虚拟空间至少有MAX_SOMEDATA * sizeof(SOMEDATA)个字节,一般情况会比它大
		//注意:g_pSomeData指向的内存地址都是64KB的整数倍
		g_pSomeData = (PSOMEDATA)VirtualAlloc(NULL, MAX_SOMEDATA * sizeof(SOMEDATA), MEM_RESERVE, PAGE_READWRITE);
		//使预定按钮无效,然后让其他按钮有效
		EnableWindow(GetDlgItem(hwnd, IDC_Reserve), FALSE);
		EnableWindow(GetDlgItem(hwnd, IDC_Index), TRUE);
		EnableWindow(GetDlgItem(hwnd, IDC_Index_Text), TRUE);
		EnableWindow(GetDlgItem(hwnd, IDC_Use), TRUE);
		EnableWindow(GetDlgItem(hwnd, IDC_Clear), TRUE);
		EnableWindow(GetDlgItem(hwnd, IDC_GarbageCollect), TRUE);
		//强制索引编辑控件获得焦点
		SetFocus(GetDlgItem(hwnd, IDC_Index));
		//强制内存映射更新
		InvalidateRect(hwnd, &g_rcMemMap, FALSE);
		break;
	case IDC_Index:
		if (codeNotify != EN_CHANGE)
			break;
		/*
		UINT GetDlgItemInt(
				HWNDhDlg, // 窗口句柄
				int nIDDlgItem, // 控件标识符(名称)
				BOOL *lpTranslated, // 布尔变量的指针
				BOOLbSigned // 有符号或无符号值);
		*/
		//得到控件的输入数值
		uIndex = GetDlgItemInt(hwnd, id, NULL, FALSE);
		if ((g_pSomeData != NULL) && chINRANGE(0, uIndex, MAX_SOMEDATA - 1))
		{
			MEMORY_BASIC_INFORMATION mbi;
			//得到g_pSomeData[uIndex]处的内存信息
			VirtualQuery(&g_pSomeData[uIndex], &mbi, sizeof(mbi));
			BOOL bOk = (mbi.State == MEM_COMMIT);
			//如果该内存已经调拨了物理存储器(内存)
			if (bOk)
			{
				//看看是否是可以被回收的
				bOk = g_pSomeData[uIndex].bInUse;
			}
			EnableWindow(GetDlgItem(hwnd, IDC_Use),!bOk);
			EnableWindow(GetDlgItem(hwnd, IDC_Clear),bOk);
		}
		//如果g_pSomeData为空或者索引不满足条件
		else
		{
			EnableWindow(GetDlgItem(hwnd, IDC_Use), FALSE);
			EnableWindow(GetDlgItem(hwnd, IDC_Clear), FALSE);
		}
		break;


	case IDC_Use:
		uIndex = GetDlgItemInt(hwnd, IDC_Index, NULL, FALSE);
		//注意:新页面总是被系统全部赋值为0
		//调拨物理存储器(内存)
		//注意哦,分配内存可不需要按照
		VirtualAlloc(&g_pSomeData[uIndex], sizeof(SOMEDATA), MEM_COMMIT, PAGE_READWRITE);
		//标记为可以被回收(也就是已调拨物理存储器)
		g_pSomeData[uIndex].bInUse = TRUE;
		EnableWindow(GetDlgItem(hwnd, IDC_Use), FALSE);
		EnableWindow(GetDlgItem(hwnd, IDC_Clear), TRUE);
		//强制Clear按钮得到焦点
		SetFocus(GetDlgItem(hwnd, IDC_Clear));
		//强制展示内存映射情况的控件更新
		InvalidateRect(hwnd, &g_rcMemMap, FALSE);

		break;
	case IDC_Clear:
		uIndex = GetDlgItemInt(hwnd, IDC_Index,NULL, FALSE);
		g_pSomeData[uIndex].bInUse = FALSE;
		EnableWindow(GetDlgItem(hwnd, IDC_Use), TRUE);
		EnableWindow(GetDlgItem(hwnd, IDC_Clear), FALSE);
		//强制Use按钮得到焦点
		SetFocus(GetDlgItem(hwnd, IDC_Use));
		
		break;
	case IDC_GarbageCollect:
		GarbageCollect(g_pSomeData, MAX_SOMEDATA, sizeof SOMEDATA);
		InvalidateRect(hwnd, &g_rcMemMap, FALSE);
		break;
	}
}

/*
	这个函数可以用于自己的应用程序,但是唯一的要求是结构的第一个成员必须是一个BOOL值,用来表示该结构是否
	正在使用
*/
//垃圾回收  pvBase为回收的结构内存地址,MAX_SOMEDATA为结构总数量,dwStructSize结构大小
VOID GarbageCollect(PVOID pvBase, DWORD dwNum, DWORD dwStructSize)
{
	//最多需要多少页才能装下这些结构
	UINT uMaxPages = (dwNum * dwStructSize / g_uPageSize);
	for (UINT uPage = 0; uPage < uMaxPages; uPage++)
	{
		//当前页面是否有其他被分配的内存
		BOOL bAnyAllocsInThisPage = FALSE;
		//该页的第一个索引
		UINT uIndex = uPage * g_uPageSize / dwStructSize;
		//该页的最后一个索引
		UINT uIndexLast = uIndex + g_uPageSize / dwStructSize;
		for (; uIndex < uIndexLast; uIndex++)
		{
			MEMORY_BASIC_INFORMATION mbi;
			VirtualQuery(&g_pSomeData[uIndex], &mbi, sizeof mbi);
			bAnyAllocsInThisPage = ((mbi.State == MEM_COMMIT) && *(PBOOL)((PBYTE)pvBase + dwStructSize * uIndex));
			//如果bAnyAllocsInThisPage为真,就停止检查当前页,因为不能撤销它
			if (bAnyAllocsInThisPage) break;
		}

		if (!bAnyAllocsInThisPage)
		{
			//回收该结构所在页的内存
			VirtualFree(&g_pSomeData[uIndex - 1], dwStructSize, MEM_DECOMMIT);
		}
	}
}

效果图:
在这里插入图片描述
Clear只起到一个把结构的可回收标志位设为FALSE,不做真实回收,只有当点击垃圾回收的时候才真正的遍历回收调拨的存储器(页面文件或者内存)。

发布了6 篇原创文章 · 获赞 0 · 访问量 295
展开阅读全文

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 数字20 设计师: CSDN官方博客

分享到微信朋友圈

×

扫一扫,手机浏览