Win32_Windows的内存管理
一 地址空间
1 地址空间
一个程序最大的寻址范围,对于Win32操作系统最大的寻址范围是2的32次方
(0 - 0xFFFFFFFF).这个寻址范围由CPU决定。CPU的寻址范围越大程序难度降低。
2 地址空间的划分
2.1 用户空间
地址范围 0 - 0x7FFFFFFF (2G),运行应用程序代码、数据等。
2.2.1 空指针区(NULL区)
地址范围 0 - 0x0000FFFF
2.2.2 用户区
地址范围 0x00010000 - 0x7FFEFFFF
2.2.3 64K禁入区
地址范围 0x7FFEFFFF - 0x7FFFFFFF
2.2 内核空间
地址范围 0x80000000 - 0xFFFFFFFF 被系统使用,运行驱动、内核的数据代码。
二 地址映射
1 内存区域
区域指一段连续的地址空间,区域的粒度和CPU的粒度、操作系统相关,目前通常都是以
64K粒度存在。地址的对齐方式是以64K为边界
区域的状态:
1)保留 - 空闲的,可以被使用
2)私有 - 已经被占有,但是还未使用
3)映像 - 程序的代码使用
4)映射 - 程序的数据使用
2 物理内存
实际可以使用的物理存储器
3 虚拟内存
使用硬盘空间作为内存扩展,也可以当作物理内存使用。
4 内存页
操作系统使用内存页的方式管理物理内存和虚拟内存,通常情况下内存页的大小为4K或者8K。
每个内存页具有自己的状态,例如:只读/可写/可执行
5 页目表
用于管理内存页的表
页目 - 页表 - 内存页
- 内存页
- 页表
- 页表
指针 31------22 21-------12 11------0
页目 页表 偏移量
6 地址空间的访问
6.1 地址空间已经存在映射好的物理内存,直接使用,返回
6.2 系统去虚拟内存中查找对应的内存页,如果未找到系统错误返回。
6.3 系统将虚拟内存的内存页切换到物理当中。
6.4 返回实际物理内存地址使用数据。
1 #include "stdafx.h" 2 #include "windows.h" 3 4 void ShowSys() 5 { 6 SYSTEM_INFO info = {0}; 7 GetSystemInfo(&info); 8 printf("内存页的大小:%d\n",info.dwPageSize); 9 printf("可用最小地址:%p\n",info.lpMinimumApplicationAddress); 10 printf("可用最大地址:%p\n",info.lpMaximumApplicationAddress); 11 printf("区域的分配粒度:%d\n",info.dwAllocationGranularity); 12 } 13 14 int main(int argc, char* argv[]) 15 { 16 17 ShowSys(); 18 return 0; 19 }
7 内存的使用
7.1 虚拟内存
适合对于大内存分配使用,一般情况下如果分配的内存大于1M
应该使用虚拟内存分配方式
7.2 堆内存
适合对于小内存分配使用,一般情况下对于小于1M的内存分配使用。
如:malloc/new
7.3 堆栈内存
系统维护的内存区
二 虚拟内存
1 虚拟内存
常用于大内存分配,分配的速度快,可以根据需要指定分配方式。
2 虚拟内存的使用
2.1 分配内存
LPVOID VirtualAlloc( LPVOID lpAddress,//NULL或者用于提交的内存地址 DWORD dwSize,//分配的大小 DWORD flAllocationType,//分配的方式 DWORD flProtect);//内存访问方式
分配最大空间小于用户区间(通常是2G)
2.2 提交内存
VirtualAlloc使用MEM_COMMIT方式,如:
pszBuf = (CHAR*)VirtualAlloc( pszBuf,//需要提交内存地址 1024 * 1024 * 1024,MEM_COMMIT,PAGE_READWRITE);
2.3 使用内存
2.4 释放内存
BOOL VirtualFree( LPVOID lpAddress,//释放的内存 DWORD dwSize,//释放的大小 DWORD dwFreeType);//释放的方式
3 内存信息
VOID GlobalMemoryStatus(LPMEMORYSTATUS lpBuffer);//获取内存信息
1 #include "stdafx.h" 2 #include "conio.h" 3 #include "windows.h" 4 5 void Status( ) 6 { //获取内存信息 7 MEMORYSTATUS status = { 0 }; 8 status.dwLength = sizeof( status ); 9 GlobalMemoryStatus( &status ); 10 printf( "TotalPhys: %u\n", status.dwTotalPhys ); 11 printf( "AvailPhys: %u\n", status.dwAvailPhys ); 12 printf( "TotalPageFile: %u\n", status.dwTotalPageFile ); 13 printf( "AvailPageFile: %u\n", status.dwAvailPageFile ); 14 printf( "TotalVirtual: %u\n", status.dwTotalVirtual ); 15 printf( "AvailVirtual: %u\n", status.dwAvailVirtual ); 16 printf( "MemoryLoad: %d\n", status.dwMemoryLoad ); 17 } 18 19 void Virtual( ) 20 { 21 Status( ); 22 //地址分配 23 CHAR * pszBuf = (CHAR *) 24 VirtualAlloc( NULL, 25 1024 * 1024 * 1024, 26 MEM_RESERVE, 27 PAGE_READWRITE ); 28 printf( "MEM_RESERVE: %p\n", pszBuf ); 29 30 Status( ); 31 32 getch( ); 33 //内存提交 34 pszBuf = (CHAR *) 35 VirtualAlloc( pszBuf, 36 1024 * 1024 * 1024, 37 MEM_COMMIT, 38 PAGE_READWRITE ); 39 printf( "MEM_COMMIT: %p\n", pszBuf ); 40 Status( ); 41 42 strcpy( pszBuf, "hello Virtual" ); 43 printf( "%s\n", pszBuf ); 44 45 Status( ); 46 getch( ); 47 48 //释放内存 49 VirtualFree( pszBuf, 50 1024 * 1024 * 1024, 51 MEM_RELEASE ); 52 } 53 54 int main(int argc, char* argv[]) 55 { 56 Virtual( ); 57 return 0; 58 }
三 堆内存
1 堆内存的特点
一般分配小数据内存,小于1M数据使用堆内存分配。
一般程序执行后,会有一个默认堆,这个堆的大小一般为1M,一个程序可以有多个堆,
通过堆内存管理器来管理堆中的内存。内存分配速度比VirtualAlloc慢
2 堆内存的使用
2.1 创建堆
HANDLE HeapCreate( DWORD flOptions,//创建标示 DWORD dwInitialSize,//初始化大小 DWORD dwMaximumSize);//最大大小
2.2 分配内存
LPVOID HeapAlloc( HANDLE hHeap,//堆的句柄 DWORD dwFlags,//分配标示 DWORD dwBytes);//分配大小
2.3 使用内存
2.4 释放内存
BOOL HeapFree( HANDLE hHeap,//堆的句柄 DWORD dwFlags,//释放标示 LPVOID lpMem);//释放的地址
2.5 释放堆
BOOL HeapDestroy(HANDLE hHeap);//堆的句柄
3 malloc/HeapAlloc/VirtualAlloc
malloc内部调用 HeapAlloc
HeapAlloc内部调用的 VirtualAlloc
malloc分配内存:
例如:100字节
| 内存头 | 100字节 | 4字节尾部标示 |
所使用 malloc分配的内存会使用这个内存头构成链表。
4 堆的信息
GetProcessHeap 当前进程默认堆的句柄
GetProcessHeaps 当前进程所有堆的句柄
1 #include "stdafx.h" 2 #include "stdlib.h" 3 #include "windows.h" 4 5 void HeapInfo( ) 6 { //默认堆的句柄 7 HANDLE hHeap = GetProcessHeap(); 8 printf( "Default Heap: %p\n", hHeap ); 9 //所有的堆的句柄 10 HANDLE hHeaps[256] = { 0 }; 11 DWORD nCount = 12 GetProcessHeaps( 256, hHeaps ); 13 printf( "All Heap: %d\n", nCount ); 14 for( DWORD nIndex=0; nIndex<nCount; nIndex++ ) 15 { 16 printf( "\t%d: %p\n", nIndex+1, 17 hHeaps[nIndex] ); 18 } 19 } 20 21 void Heap( ) 22 { 23 HeapInfo( ); 24 25 //创建堆 26 HANDLE hHeap = HeapCreate( 27 HEAP_GENERATE_EXCEPTIONS, 28 1024 * 1024, 0 ); 29 printf( "HeapCreate: %p\n", hHeap ); 30 31 HeapInfo( ); 32 33 //内存分配 34 CHAR * pszBuf = ( CHAR * ) 35 HeapAlloc( hHeap, HEAP_ZERO_MEMORY, 100 ); //分配后初始化为0 36 printf( "HeapAlloc: %p\n", pszBuf ); 37 38 strcpy( pszBuf, "hello Heap" ); 39 printf( "%s\n", pszBuf ); 40 41 //内存释放 42 HeapFree( hHeap, 0, pszBuf ); 43 44 //释放堆 45 HeapDestroy( hHeap ); 46 47 HeapInfo( ); 48 } 49 50 int main(int argc, char* argv[]) 51 { 52 CHAR * pszBuf = (CHAR *)malloc( 1024 ); 53 54 Heap( ); 55 return 0; 56 }
四 堆栈内存
堆栈都是小数据的使用由系统维护,栈的大小一般在1M左右,
例如:Windows下可以使用 _alloca 函数从栈上分配 内存,很少会用
五 内存映射文件
1 内存映射文件
可以将文件映射成内存,我们可以像使用内存一样使用文件。
2 内存映射文件的使用
2.1 创建或打开一个文件
CreateFile
2.2 创建内存映射文件
HANDLE CreateFileMapping( HANDLE hFile,//文件句柄 LPSECURITY_ATTRIBUTES lpFileMappingAttributes,//安全属性 DWORD flProtec,//保护模式 DWORD dwMaximumSizeHigh,//大小的高32位 DWORD dwMaximumSizeLow,//大小的低32位 LPCTSTR lpName);//文件映射内核对象的名称
2.3 映射成内存地址
LPVOID MapViewOfFile( HANDLE hFileMappingObject,//文件映射句柄 DWORD dwDesiredAccess,//访问模式 DWORD dwFileOffsetHigh,//地址偏移高32位 DWORD dwFileOffsetLow,//地址偏移低32位 DWORD dwNumberOfBytesToMap);//要映射的字节数
2.4 使用内存
2.5 制裁映射
BOOL UnmapViewOfFile(LPCVOID lpBaseAddress);//卸载的地址
2.6 关闭内存映射文件
CloseHandle
2.7 文件关闭
CloseHandle
1 #include "stdafx.h" 2 #include "windows.h" 3 4 void Map( ) 5 { 6 //创建文件 7 HANDLE hFile = CreateFile( "C:\\map.dat", 8 GENERIC_READ|GENERIC_WRITE, 9 0, NULL, CREATE_ALWAYS, 10 FILE_ATTRIBUTE_NORMAL, NULL ); 11 //创建文件映射 12 HANDLE hMap = CreateFileMapping( hFile, NULL, 13 PAGE_READWRITE, 0, 1024 * 1024, NULL ); 14 //映射地址 15 CHAR * pszText = (CHAR *)MapViewOfFile( 16 hMap, FILE_MAP_ALL_ACCESS, 17 0, 0, 1024 * 1024 ); 18 //使用内存 19 strcpy( pszText, "Hello File Mapping" ); 20 printf( "%s\n", pszText ); 21 //卸载地址 22 UnmapViewOfFile( pszText ); 23 //关闭文件映射 24 CloseHandle( hMap ); 25 //关闭文件 26 CloseHandle( hFile ); 27 } 28 29 int main(int argc, char* argv[]) 30 { 31 Map( ); 32 return 0; 33 }