Windows内存地址空间
- 地址空间
程序中可以寻址的最大范围。对于32位操作系统,
地址空间范围为0-4G(2^32),地址空间越大,
相对程序的编写就会容易。 - 地址空间的划分
- 用户地址空间 0 - 2G(7FFFFFFF )
存放用户的程序和数据。
用户空间的代码是不能访问内核空间的数据和代码。- 空指针区(NULL区,0-64K)系统将地址小于64K指针,都认为是空指针。
- 用户区
- 64K禁入区(0x7FFEFFFF - 0x7FFFFFFF )
- 内核地址空间 2G - 4G
存放内核的代码和数据,例如系统驱动。
内核空间代码是可以访问用户空间。
- 用户地址空间 0 - 2G(7FFFFFFF )
windows内存
- 区域
区域就是连续的一块内存。区域的大小一般为64K或者64K倍数。每个区域都有自己的状态:- 空闲:没有被使用
- 私有:被预定的区域
- 映像:存放代码
- 映射:存放数据
- 物理内存
系统可以使用的实际内存。CPU可以直接访问的内存。 虚拟内存(硬盘交换文件)
将硬盘文件虚拟成内存使用。(pagefile.sys 文件)
CPU如果要访问虚拟内存数据,必须将虚拟内存数据
放到物理内存。- 内存页
系统管理地址的最小单位。内存页大小为4K,每个
内存页有自己的权限。 页目表
指针地址
31 22 21 12 11 0
|-----------|------------|--------------|
10位 10位 12位2^10=1024 1024 4K 页目 页表 页内偏移地址
- 从内存获取数据过程
- 根据地址在物理内存中查找相应的位置。如果找到物理内存,取回数据。如果未找到,执行下一步.
- 根据地址去虚拟内存中查找相应的位置。如果未找到,那么该地址没有内存空间,返回错误。如果找到,执行下一步.
- 将该地址所在内存页,置换到物理内存中,同时将原物理内存数据,存入到虚拟内存中。
- 将物理内存中的数据返回给使用者。
- 内存分配
- 虚拟内存分配-适合大内存分配,一般是1M之上的内存。
- 堆内存分配-适合小内存分配,一般是1M以下的内存。
malloc/new - 栈内存分配-适合小内存分配,一般是1M以下的内存。
虚拟内存分配
- 虚拟内存分配
速度快,大内存效率高。将内存和地址分配分别执行,可以在需要的时候再提交内存。常用字大型电子表格等处理。 - 虚拟内存使用
- 内存分配
LPVOID VirtualAlloc( LPVOID lpAddress,// NULL或提交地址 SIZE_T dwSize, //分配的大小 DWORD flAllocationType, //分配方式 DWORD flProtect //内存访问方式 ); 分配成功返回地址
- 分配方式:
MEM_COMMIT - 提交内存,分配之后返回地址和内存空间
MEM_RESERVE- 保留地址,分配之后只返回地址,内存空间不生成。要使用内存必须再次提交。
- 使用
- 释放
BOOL VirtualFree(
LPVOID lpAddress,//释放地址
SIZE_T dwSize, //释放的大小0
DWORD dwFreeType //释放方式
);
* 释放方式:
MEM_DECOMMIT - 只释放内存,不释放地址
MEM_RELEASE - 地址和内存都释放
堆内存 Heap
- 堆内存分配
适合分配小内存,一般是小于1M的内存。一般每个程序都有自己的堆,默认大小为1M,会根据使用情况进行调整。 - 堆的使用
- 堆的信息
GetProcessHeap - 获得程序的第一个堆
GetProcessHeaps - 获取程序中所有的堆 - 创建堆
HANDLE HeapCreate( DWORD flOptions,//创建选项 SIZE_T dwInitialSize, //初始化大小1024*1024 SIZE_T dwMaximumSize //最大值0 ); 成功返回堆句柄
- 从堆中分配内存(获取堆中内存的地址)
LPVOID HeapAlloc(
HANDLE hHeap, //堆句柄
DWORD dwFlags, //分配方式
SIZE_T dwBytes //分配大小210241024
); 成功返回地址 - 使用内存
释放内存
BOOL HeapFree(
HANDLE hHeap, // 堆句柄
DWORD dwFlags, // 释放方式
LPVOID lpMem // 释放地址
);- 销毁堆
BOOL HeapDestroy(
HANDLE hHeap //堆句柄
);
当堆被销毁后,使用该堆分配内存全都被销毁。
- 堆的信息
- VirtualAlloc/HeapAlloc/malloc/new在Windows平台上,函数调用关系:
new/malloc -> HeapAlloc。。。。。
栈内存
栈内存-每个线程都具有自己的栈,默认大小1M。
一般是系统维护栈。
Windows提供了 _alloca, 可以在栈上分配内存。
- 内存映射文件
将文件映射成内存来使用。当使用内存时,就是在使用文件。
内存映射文件的使用- 创建或打开文件CreateFile
- 创建内存映射文件
HANDLE CreateFileMapping( HANDLE hFile, //文件句柄 LPSECURITY_ATTRIBUTES lpAttributes, //安全属性 DWORD flProtect,//访问方式 DWORD dwMaximumSizeHigh,//内存映射文件大小的高32 DWORD dwMaximumSizeLow, //内存映射文件大小的低32 LPCTSTR lpName //命名,可以为NULL ); 创建成功返回句柄
- 获取内存映射文件某个地址
LPVOID MapViewOfFile( HANDLE hFileMappingObject,//内存映射文件句柄 DWORD dwDesiredAccess, //访问模式 DWORD dwFileOffsetHigh, //偏移量的高32位 DWORD dwFileOffsetLow, //偏移量的低32位 SIZE_T dwNumberOfBytesToMap //不使用 //映射的字节数量 ); 成功返回地址
dwFileOffsetHigh和dwFileOffsetLow合成的偏移量,必须是区域粒度的整数倍(64K的整数倍)
- 使用内存
- 将 地址 和 内存映射文件的 某个部分分开
BOOL UnmapViewOfFile(
LPCVOID lpBaseAddress //卸载地址
); - 关闭内存映射文件
CloseHandle – 一旦关闭,就没了 - 关闭文件
CloseHandle