windows基础编程 -- 内存管理

前言

理解windows系统是怎么管理内存和地址之间的关系将能更好的理解很多和内存分配与内存异常的问题,同时对数据的存储和内存的管理也有更深的体会。

内存和地址

  • 内存和地址是两个概念,准确来说,内存是真实的,地址是虚拟的,地址只是操作系统管理数据的一种方式,就好像取地名一样,而内存就是内存条,它是CPU唯一能够交换数据的地方,包括从硬盘读数据都得经过内存。
  • 内存页是系统管理内存的最小单位,它的大小为4K,每个内存页有自己的权限。这什么意思呢,也就是32位系统它的地址空间有0~0xFFFFFFFF共4G地址空间,对于这4G地址,系统按每4K地址来管理,也就是2^20*4K,即1024*1024个内存页,而每1024个内存页对应一个内表,所有页表对应一个页目,具体可参考下图

  • windows基础编程 -- 内存管理_第1张图片
    我们将每4K(2^12)地址作为1个内存页,然后每1024个内存页记作一张内存表,然后1024张内存表叠加起来就可以构成4G地址了,也就是操作系统管理地址的虚拟表示方式。
    实际上,操作系统拿得一个地址数据,也就是32位指针,它是这么解析的, 首先把高位31-22位记作页目,它对应1024张页表,找到哪一张页表以后,从21-12位这张页表中找出1024中哪一个内存页,最后11-0记作内存偏移地址,它能从4K地址中找出具体哪一个,这样就对应到任意一个地址单位了。
  • 内存分为物理内存和虚拟内存,物理内存就是真实的内存条,所有的数据都必须经过这里才能和CPU进行数据交互,而虚拟内存是虚拟文件,它实际上电脑上的硬盘文件,实际的作用当作物理内存的储备来使用,存放一些不经常使用的数据。

映射

  • 我们使用的所有地址都是交由操作系统管理的,所谓真实有效的地址也就是这个地址与内存上的单元(物理或虚拟)建立了一对一的映射,而操作一切没有映射的地址,操作系统因为去内存上找不到该地址都会段错误。
  • 映射的基本单位也是4K,操作系统最小会一次映射4K地址到内存上。
  • 每次操作系统解析一个地址时,首先会去物理内存上查找有没对应的地址单元,没有去虚拟内存上查找,如果有把该单元放到物理内存里,把原物理内存里的数据放到虚拟内存里,再继续去操作物理内存。

内存分配

windows常规3种内存分配策略
    > 虚拟内存分配  一般1M以上内存申请
    > 堆内存分配    一般1M以下内存申请
    > 栈内存分配    一般1M以下内存申请
这里要说明的是,虚拟内存分配不一定给的就是虚拟内存地址,可能也还是物理内存地址,根据数据的使用活跃性决定。
堆内存对应内核中维护的一个堆结构体体句柄,需要使用HeapCreate然后使用HeapAlloc才能使用。
具体内存调用函数关系如下:new/malloc -> HeapAlloc -> VirtualAlloc

内存申请函数
LPVOID VirtualAlloc(
LPVOID lpAddress, // NULL为申请+提交/地址为提交
DWORD dwSize, // 空间大小
DWORD flAllocationType,
// 分配方式
DWORD flProtect //内存访问方式
);
成功申请/提交返回地址,这个函数可以先申请而不提交,即占有一部分虚拟地址,而这些地址又没映射到内存上,只有再提交以后操作这部分地址才不会报错。 或者,可以直接申请+提交,这样就可以直接使用了。

使用VirtualFree来释放这部分内存
使用GlobalMemoryStatus 可以查看所有内存使用情况,包括物理内存,虚拟内存和可使用地址空间。

内存文件映射

内存文件映射也就是把硬盘上的文件映射到内存中,主要用于两个进程之间的通信,具体流程如下:

- CreateFile 创建一个硬盘文件
- CreateFileMapping 创建一个文件映射结构,返回该结构的句柄
(HANDLE hFile, //文件句柄
LPSECURITY_ATTRIBUTES lpFileMappingAttributes,
// 安全属性设为NULL
DWORD flProtect, // 访问方式
DWORD dwMaximumSizeHigh, // 作为映射的文件大小高32字节
DWORD dwMaximumSizeLow, // 文件大小低32字节
LPCTSTR lpName // 内存映射对象结构名称
);
- MapViewOfFile 将硬盘文件和本进程地址空间建立映射
HANDLE hFileMappingObject, // 内存映射对象句柄
DWORD dwDesiredAccess, // 访问权限
DWORD dwFileOffsetHigh, // 文件内地址偏移高32字节
DWORD dwFileOffsetLow, // 文件内地址偏移低32字节
DWORD dwNumberOfBytesToMap // 映射字节数,为0表示文件大小全映射
);
- 使用返回的地址操作,然后调用UpMapViewOfFile解除映射
- 使用CloseHandle关闭内存映射句柄和对应的文件
- 注释:内存映射结构里记录了用作映射的文件句柄,可映射的大小和该内存映射的名称。在另一个进程中掉用OpenFileMapping即可根据该名称找到这个句柄。

你可能感兴趣的:(window编程)