这一节看看内存管理相关的信息
首先看看虚拟内存
虚拟地址空间
32位系统 --- 4GB = 232
64 位系统 ---- 16EB = 264
虚拟内存表
当一个应用程序从硬盘加载到RAM时,首先系统为应用程序保留一定的地址区域,将一些必须的数据加载到内存中,然后将一些不是必须的数据加载到页文件(虚拟内存)中,页文件的大小有操作系统控制。在程序运行过程中,如果需要某个文件,就先去RAM中寻找,如果寻找不到,就去页文件中寻找,如果还寻找不到就发出数据访问违规异常。
过程如下:
每个页文件的保护属性都不同,页文件的页面拥有不同的属性,包括
除了上面介绍的保护属性外,还有3个保护属性标志,即PAGE_NOCACHE,PAGE_WRITECOMBINE和PAGE_GUARD。可以用OR逐位将它们连接,以便将这3个标志用于任何一个保护属性(PAGE_NOCACHE除外)。
第一个保护属性标志PAGE_NOCACHE用于停用已提交页面的高速缓存。一般情况下最好不要使用该标志,因为它主要是供需要处理内存缓冲区的硬件设备驱动程序的开发人员使用的。
第二个保护属性PAGE_WRITECOMBINE也是供设备驱动程序开发人员使用的。它允许把单个设备的多次写入合并在一起,以便提高运行性能。
最后一个保护属性标志PAGE_GUARD可以在页面上写入一个字节时使应用程序收到一个通知(通过一个异常条件)。该标志有一些非常巧妙的用法。Windows2000在创建线程堆栈时使用该标志。
虚拟内存的区域类型共有四个值,即空闲、私有、映像或映射。
数据对齐
数据对齐并不是操作系统的内存结构的一部分,而是CPU结构的一部分。
当CPU访问正确对齐的数据时,它的运行效率最高。当数据大小的数据模数的内存地址是0时,数据是对齐的。
当CPU试图读取的数据值没有正确对齐时,CPU可以执行两种操作之一。即它可以产生一个异常条件,也可以执行多次对齐的内存访问,以便读取完整的未对齐数据值。
X86CPU和AlphaCPU的对齐方式不同。
虚拟内存相关的函数
获取系统信息相关的函数GetSystemInfo()
void WINAPI GetSystemInfo( _Out_ LPSYSTEM_INFO lpSystemInfo//结构体信息 );
结构体如下:
1 typedef struct _SYSTEM_INFO { 2 union { 3 DWORD dwOemId; // Obsolete field...do not use 4 struct { 5 WORD wProcessorArchitecture;//CPU结构 6 WORD wReserved;//保留字段 7 } DUMMYSTRUCTNAME; 8 } DUMMYUNIONNAME; 9 DWORD dwPageSize;//页面大小 10 LPVOID lpMinimumApplicationAddress;//最小内存地址 11 LPVOID lpMaximumApplicationAddress;//最大内存地址 12 DWORD_PTR dwActiveProcessorMask;//哪个CPU是活动的 13 DWORD dwNumberOfProcessors;//CPU数目 14 DWORD dwProcessorType;//CPU类型 15 DWORD dwAllocationGranularity;//保留的内存空间区域的分配粒度, 16 WORD wProcessorLevel; //CPU结构细节 17 WORD wProcessorRevision; //CPU等级 18 } SYSTEM_INFO, *LPSYSTEM_INFO;
其中与内存相关的参数如下:
其他与内存无关的成员函数
现在来看看如何使用这个函数
1 //获取系统参数 2 #include "windows.h" 3 #include "iostream" 4 using namespace std; 5 6 int main() 7 { 8 SYSTEM_INFO sysinfo;//声明一个结构体 9 GetSystemInfo(&sysinfo); 10 11 cout<<"页面大小:"<<sysinfo.dwPageSize<<endl; 12 cout<<"最小内存地址:"<<sysinfo.lpMinimumApplicationAddress<<endl; 13 cout<<"最大内存地址:"<<sysinfo.lpMaximumApplicationAddress<<endl; 14 cout<<"保留的地址空间区域的分配粒度:"<<sysinfo.dwAllocationGranularity<<endl; 15 cout<<"CPU数目:"<<sysinfo.dwNumberOfProcessors<<endl; 16 cout<<"活动CPU:"<<sysinfo.dwActiveProcessorMask<<endl; 17 cout<<"处理器类型:"<<sysinfo.dwProcessorType<<endl; 18 cout<<"处理器结构:"<<sysinfo.wProcessorArchitecture<<endl; 19 cout<<"处理器等级:"<<sysinfo.wProcessorLevel<<endl; 20 cout<<"处理器版本:"<<sysinfo.wProcessorRevision<<endl; 21 22 getchar(); 23 return 0; 24 }
虚拟内存的状态GlobalMemoryStatus()
1 //这是旧版的函数 2 void GlobalMemoryStatus( 3 __out LPMEMORYSTATUS lpBuffer 4 ); 5 typedef struct _MEMORYSTATUS { 6 DWORD dwLength; 7 DWORD dwMemoryLoad; 8 SIZE_T dwTotalPhys; 9 SIZE_T dwAvailPhys; 10 SIZE_T dwTotalPageFile; 11 SIZE_T dwAvailPageFile; 12 SIZE_T dwTotalVirtual; 13 SIZE_T dwAvailVirtual; 14 } MEMORYSTATUS, *LPMEMORYSTATUS;
//新版的函数,支持4G以上虚拟内存,64位宽度
1 //新版函数更加强大 2 BOOL GlobalMemoryStatusEx( 3 __out LPMEMORYSTATUSEX lpBuffer 4 ); 5 typedef struct _MEMORYSTATUSEX { 6 DWORD dwLength;//结构体大小 7 DWORD dwMemoryLoad;//已加载的内存比例 8 DWORDLONG ullTotalPhys;//物理内存大小 9 DWORDLONG ullAvailPhys;//当前可用物理内存大小 10 DWORDLONG ullTotalPageFile;//总的页面大小 11 DWORDLONG ullAvailPageFile;//当前可用的页面大小 12 DWORDLONG ullTotalVirtual;// 每个进程的地址空间中私有的总字节数 13 DWORDLONG ullAvailVirtual;// 进程的空闲地址空间的数量 14 DWORDLONG ullAvailExtendedVirtual;//保留,0 15 } MEMORYSTATUSEX, *LPMEMORYSTATUSEX;
注意事项:
在调用GlobalMemoryStatus之前,必须将dwLength成员初始化为结构体的大小,即一个MEMORYSTATUS结构的大小。
函数使用如下:
1 //获取虚拟内存状态 2 cout<<"\n虚拟内存状态\n"<<endl; 3 //虚拟内存状态 4 MEMORYSTATUSEX ms; 5 ms.dwLength = sizeof(MEMORYSTATUSEX);//这个参数必须首先初始化 6 GlobalMemoryStatusEx(&ms); 7 cout<<"结构体大小:"<<ms.dwLength<<endl; 8 cout<<"已加载的内存比例:"<<ms.dwMemoryLoad<<endl; 9 cout<<"物理内存大小:"<<ms.ullTotalPhys<<endl; 10 cout<<"可用内存大小:"<<ms.ullAvailPhys<<endl; 11 cout<<"总的页面数:"<<ms.ullTotalPageFile<<endl; 12 cout<<"可用页面数:"<<ms.ullAvailPageFile<<endl; 13 cout<<"每个进程的地址空间中私有的总字节数:"<<ms.ullTotalVirtual<<endl; 14 cout<<"进程的空闲地址空间的数量:"<<ms.ullAvailVirtual<<endl;
地址空间状态VirtualQuery()
通过该函数或获取进程地址空间的信息,如大小,存储类型,保护属性等。
1 SIZE_T WINAPI VirtualQuery( 2 _In_opt_ LPCVOID lpAddress,//要查询的进程的地址空间信息的虚拟内存地址 3 _Out_ PMEMORY_BASIC_INFORMATION lpBuffer,//结构体 4 _In_ SIZE_T dwLength//本结构体的大小 5 ); 6 //其中参数的详细情况如下 7 typedef struct _MEMORY_BASIC_INFORMATION { 8 PVOID BaseAddress;//进程地址 9 PVOID AllocationBase;//基地址 10 DWORD AllocationProtect;//保护属性 11 SIZE_T RegionSize;//所有页面大小 12 DWORD State;//相邻界面状态 13 DWORD Protect;//相邻界面保护属性 14 DWORD Type;//相邻界面的物理存储器类型 15 } MEMORY_BASIC_INFORMATION, *PMEMORY_BASIC_INFORMATION;
参数介绍如下:
由一个进程查询另一个进程的信息 VirtualAllocEx()
调试程序会调用这个函数,查看其他进程的信息
1 //由一个进程查询另一个进程的信息 2 LPVOID VirtualAllocEx( 3 __in HANDLE hProcess,//进程句柄 4 __in_opt LPVOID lpAddress,//查询地址 5 __in SIZE_T dwSize,//与分配的页面大小 6 __in DWORD flAllocationType,//分配类型 7 __in DWORD flProtect //保护属性 8 );
如何查询地址状态
1 //如何查询地址状态 2 cout<<"地址空间的状态"<<endl; 3 MEMORY_BASIC_INFORMATION mbi; 4 HANDLE hProcess = NULL; 5 TCHAR path[1024] = {0}; 6 DWORD dwResult = VirtualQuery(hProcess,&mbi,sizeof(mbi)); 7 while(dwResult) 8 { 9 cout<<"内存地址起始地址:"<<hProcess<<endl; 10 switch(mbi.State) 11 { 12 case MEM_COMMIT: 13 cout<<"已经物理分配"<<endl; 14 break; 15 case MEM_RESERVE: 16 cout<<"保留"<<endl; 17 break; 18 case MEM_FREE: 19 cout<<"空闲没有分配"<<endl; 20 break; 21 default: 22 break; 23 } 24 switch(mbi.Type) 25 { 26 case MEM_IMAGE: 27 cout<<"该地址为文件镜像"<<endl; 28 GetModuleFileName((HINSTANCE)hProcess,path,1024); 29 cout<<path<<endl; 30 break; 31 case MEM_MAPPED: 32 cout<<"已经映射了"<<endl; 33 break; 34 case MEM_PRIVATE: 35 cout<<"私有的空间"<<endl; 36 break; 37 default: 38 break; 39 } 40 getchar(); 41 cout<<endl; 42 hProcess=(PBYTE)hProcess+mbi.RegionSize; 43 dwResult=VirtualQuery(hProcess,&mbi,sizeof(MEMORY_BASIC_INFORMATION)); 44 }