文章目录

  • 入坑(全网都是这一个的改编)
  • 出坑尝试
  • 出坑的正确打开方式
  • 小小总结一下
  • 结语

实验题目:系统内存使用统计 一、实验目的 1、了解Windows内存管理机制,了解页式存储管理技术。 2、熟悉Windows内存管理基本数据结构。 3、使用Windows内存管理基本API的使用 二、实验要求 1、使用Windows系统提供的函数和数据结构显示系统存储空间的使用情况。 2、内存和虚拟存储空间变化时,给出系统显示变化结果。 3、分析实验结果。

入坑(全网都是这一个的改编)

错误代码(但大家都在用):

#include "stdio.h"
#include "windows.h"

void MemoryStatus(void)                             //统计内存的状态
{
	MEMORYSTATUS lpmemory;

	GlobalMemoryStatus(&lpmemory);//此函数用来获得当前可用的物理和虚拟内存信息

	printf("物理内存总大小: %dMB\n", lpmemory.dwTotalPhys / (1024 * 1024));
	printf("可用物理内存: %dMB\n", lpmemory.dwAvailPhys / (1024 * 1024));
	printf("页文件总大小: %dMB\n", lpmemory.dwTotalPageFile / (1024 * 1024));
	printf("可用页文件大小: %dMB\n", lpmemory.dwAvailPageFile / (1024 * 1024));
	printf("虚拟地址空间总大小: %dMB\n", lpmemory.dwTotalVirtual / (1024 * 1024));
	printf("可用虚拟地址空间大小:%dMB\n", lpmemory.dwAvailVirtual / (1024 * 1024));
	printf("内存加载率: %d%% \n", lpmemory.dwMemoryLoad);
}

int main()
{

	LPVOID  Virtualbase;
	char *string;
	printf("================当前内存的使用情况================\n");
	MemoryStatus();//获取当前的内存状态
	printf("\n\n现在开始分配10MB物理内存和100MB虚拟内存\n\n");
	string = (char *)malloc(10 * 1024 * 1024); //分配物理内存
	Virtualbase = VirtualAlloc(NULL, 100 * 1024 * 1024 , MEM_COMMIT, PAGE_READWRITE);             //分配虚拟内存
	if (Virtualbase == NULL)	printf("虚拟内存分配失败\n");
	
	printf("================分配完之后的内存状态如下================\n");
	MemoryStatus();
	printf("\n\n现在开始分配10MB物理内存和100MB虚拟内存\n\n");
	free(string);  //释放物理内存
	if (VirtualFree(Virtualbase, 0, MEM_RELEASE)==0) //释放虚拟内存
		printf("释放虚拟内存失败!!\n");
	
	printf("================释放完之后的内存状态如下================\n");
	MemoryStatus();

	return 0;

}

运行结果:

windows management instrumentation内存占用高_windows

windows management instrumentation内存占用高_物理内存_02

windows management instrumentation内存占用高_操作系统_03

结果分析:

(1)对于物理内存,我选择分配10MB(对于MB分配的时候,这个单位应该是1024*1024),但是分配之后的结果出现了三种:大于、小于、等于10MB的都有;另外,释放完之后一般是回不到最初的状态。

(2)对于虚拟内存,分配的是100MB,结果显示分配的大小总是:分配的虚拟内存+分配的物理内存,释放完之后都能回到最初的状态。

这已经出现问题了,完全不符合预期结果?!是的,真的达不到预期!!!

即使从分页管理方式碎片、用户行为不能对内存修改等这样的角度,总有说不通的地方。

出坑尝试

从老师那里得知,malloc申请的是虚拟内存,因此,尝试将malloc换成new。 new的正确打开方式:

char *string=new char[10 * 1024 * 1024];

释放new的正确打开方式:

delete string;

观察运行结果:

windows management instrumentation内存占用高_内存管理_04

事实上,和malloc没什么区别。

原来new在Windows中也是在堆中分配,应该也是虚拟内存。

出坑的正确打开方式

最简单的方法就是:去了解windows系统的内存管理机制 (不过,网上这方面的资料真的不多,原创的更是少) 这里贴出来查到的一些优质文章:全面介绍Windows内存管理机制及C++内存分配实例(一):进程空间全面介绍Windows内存管理机制及C++内存分配实例(二):内存状态查询全面介绍Windows内存管理机制及C++内存分配实例(三):虚拟内存 改后的代码:

#include<stdio.h>
#include<Windows.h>
#include<iostream>
using namespace std;

//尝试调用Windows API激活Lock Pages in Memory权限
BOOL LoggedSetLockPagesPrivilege(HANDLE hProcess, BOOL bEnable)
{
	struct {
		DWORD Count;//数组的个数
		LUID_AND_ATTRIBUTES Privilege[1];
	} Info;

	HANDLE Token;

	//打开本进程的权限句柄
	BOOL Result = OpenProcessToken(hProcess,TOKEN_ADJUST_PRIVILEGES,&Token);
	if(Result != TRUE)
	{
		printf("不能打开进程的权限句柄\n");
		return FALSE;
	}
	else
	{
		printf("能打开进程的权限句柄\n");
	}

	//只改变一个属性
	Info.Count = 1;
	//准备激活
	if (bEnable)
		Info.Privilege[0].Attributes = SE_PRIVILEGE_ENABLED;
	else
		Info.Privilege[0].Attributes = 0;

	//根据权限名字找到LGUID
	Result = LookupPrivilegeValue(NULL,SE_LOCK_MEMORY_NAME,&(Info.Privilege[0].Luid));
	if (Result != TRUE)
	{
		printf("无法获取内存中锁定页SE_LOCK_MEMORY_NAME的权限\n");
		return FALSE;
	}
	else
		printf("可获取内存中锁定页SE_LOCK_MEMORY_NAME的权限\n");

	// 激活Lock Pages in Memory权限
	Result = AdjustTokenPrivileges(Token, FALSE, (PTOKEN_PRIVILEGES)&Info, 0, NULL, NULL);
	if (Result != TRUE)
	{
		printf("不能调整进程句柄权限", GetLastError());
		return FALSE;
	}
	else
	{
		if (GetLastError() != ERROR_SUCCESS)
		{
			printf("不能使用内存中锁定页SE_LOCK_MEMORY_NAME权限\n");
			printf("请检查本地权限\n");
			printf("\n");
			return FALSE;
		}

	}
	CloseHandle(Token);
	return TRUE;
}


//内存和虚拟存储空间变化情况
void D_F()
{

	const int content=100;
	MEMORYSTATUS memStatusVirtual;
	GlobalMemoryStatus(&memStatusVirtual);

	PVOID pVirtual = VirtualAlloc(NULL, content * 1024 * 1024, MEM_RESERVE | MEM_PHYSICAL, PAGE_READWRITE);
	if (pVirtual == NULL)
		cout << "没有那么大连续进程空间!" << endl;

	MEMORYSTATUS memStatusVirtual2;
	GlobalMemoryStatus(&memStatusVirtual2);

	cout << "=========分配虚拟内存(可用进程空间)=========" << endl;
	cout << "减少物理内存=" << memStatusVirtual.dwAvailPhys - memStatusVirtual2.dwAvailPhys << endl;
	cout << "减少可用页文件=" << memStatusVirtual.dwAvailPageFile - memStatusVirtual2.dwAvailPageFile << endl;
	cout << "减少可用进程空间="
		<< memStatusVirtual.dwAvailVirtual - memStatusVirtual2.dwAvailVirtual << endl;
	cout << endl;
	if (VirtualFree(pVirtual, 0, MEM_RELEASE) == 0)//释放虚拟内存
		printf("释放虚拟内存失败\n");
	
	MEMORYSTATUS memStatusVirtual3;
	GlobalMemoryStatus(&memStatusVirtual3);
	cout << "=========释放虚拟内存(可用进程空间)=========" << endl;
	cout << "增加可用进程空间="
		<< memStatusVirtual3.dwAvailVirtual- memStatusVirtual2.dwAvailVirtual << endl << endl;
	cout << endl;

	LoggedSetLockPagesPrivilege(GetCurrentProcess(), true);//尝试调用Windows API激活Lock Pages in Memory权限

	//物理内存的变化情况
	SYSTEM_INFO sysInfo;
	GetSystemInfo(&sysInfo);

	ULONG_PTR pages = (ULONG_PTR)100 * 1024 * 1024 / sysInfo.dwPageSize;
	ULONG_PTR *frameArray = new ULONG_PTR[pages];

	//如果没激活权限,是不能调用这个方法的,可以调用,但是返回FALSE
	BOOL flag = AllocateUserPhysicalPages(GetCurrentProcess(), &pages, frameArray);

	if (flag == false)
	{
		cout << "=========物理内存分配=========" << endl;
		cout << "分配物理内存失败!" << endl;
		cout << endl << endl;
		system("pause");
	}
	else
	{
		MEMORYSTATUS memStatusVirtual4;
		GlobalMemoryStatus(&memStatusVirtual4);

		cout << "=========分配物理内存=========" << endl;
		cout << "减少物理内存=" << memStatusVirtual3.dwAvailPhys - memStatusVirtual4.dwAvailPhys << endl;
		cout << "减少可用页文件=" << memStatusVirtual3.dwAvailPageFile - memStatusVirtual4.dwAvailPageFile << endl;
		cout << "减少可用进程空间=" << memStatusVirtual3.dwAvailVirtual - memStatusVirtual4.dwAvailVirtual << endl << endl;

		MEMORYSTATUS memStatusVirtual5;
		GlobalMemoryStatus(&memStatusVirtual5);
		cout << "=========释放物理内存=========" << endl;
		cout << "增加物理内存=" << memStatusVirtual5.dwAvailPhys - memStatusVirtual4.dwAvailPhys << endl;
		
	}
}

int main()
{
	D_F();	
	return 0;
}

运行结果:

windows management instrumentation内存占用高_c++_05

windows management instrumentation内存占用高_操作系统_06

结果分析:

本实验采取了先对虚拟内存进行分配和释放,再对物理内存进行分配和释放的方式,通过Windows系统提供的函数和数据结构显示观察了虚拟内存空间和物理内存空间的变化,显示结果如以上两图所示。通过实验结果分析,具体如下:

(1)对于虚拟内存来说,分配时有时会产生页目和页表放在物理内存里,相应地物理内存会减小(减少的物理内存比较小),释放分配的虚拟内存时,增加的虚拟内存空间大小=减少的虚拟内存空间大小,符合预期结果。

(2)对于物理内存来说,用户行为往往不能改变物理内存的分配和释放,在本实验中,对激活物理内存中的锁定页进行了尝试,虽然能打开进程的权限句柄并获取到内存锁定页的权限,但是却不能使用内存锁定页的权限,所以最终无法分配物理内存。

(3)如果想要进一步解决不能使用内存中锁定页权限的问题,可以通过查阅资料,检查本地权限,然后对其尝试不同的方式进行修改。

(终于可以把自己说服了)

小小总结一下

(1)malloc和new在windows系统中分配的都是虚拟内存。 (2)如果想要分配物理内存,需要调用allocateuserphysicalpages命令。(但是,使用这个API之前,需要激活内存中锁定页权限,因为用户行为是不能对物理内存进行修改的)