掌握Windows系统内存管理器的基本概念,并了解其内存管理机制,有如下优点:
- 拓展软件问题的解决思路
- 帮助定位软件问题
- 发现软件中存在的可优化点,并提供优化方向
本文分三个方向对Windows内存管理进行概述。
一、Windows系统架构
首先,我们了解下用户模式和内核模式。
1)用户模式
- 固定的系统支持进程:登录进程winlogon.exe、会话管理器进程Smss.exe等;
- 服务进程:进程管理器、假脱机服务,一般是系统启动后自动启动,无用户交互界面,后台一直运行;
- 用户应用程序:windows32位、windows64位;
- 环境子系统:实现了操作系统环境的部分支持,当今windows系统只有windows子系统,提供win API;
- 子系统DLL:用户程序通过子系统DLL调用windows系统内部服务。
2)内核模式
- 执行体:Ntoskrnl.exe上层,包含基本的操作系统服务,如内存管理、进程线程管理、安全性、I/O、网络和跨进程通信;
- 内核: Ntoskrnl.exe下层,由一组低层次的操作系统功能构成,如线程调度,中断和异常分发,以及多处理器同步。为执行体提供服务以实现更高层次的功能;
- 设备驱动程序: Win32K.sys,既包括硬件设备驱动程序(用户I/O转为设备I/O),也包括软件设备驱动程序(文件系统和网络驱动程序);
- 硬件抽象层:Hal.dll,把内核、设备驱动程序、windows执行体的其余部分,跟与平台相关的硬件差异隔离开来;
- 窗口和图形:实现了图形用户界面函数,比如对窗口的处理,用户界面控件,以及绘制等。
然后,我们看下更详细的架构图:
其中,NTDLL.DLL负责用户模式与内核模式之间的切换;内存管理器是内核模式下执行体组件之一,实现了一种内存管理方案。
二、内存管理中的基本概念
内存管理是利用windows系统执行体组件之一——内存管理器实现的内存管理机制。 我们写代码中经常遇到地址和内存的概念,它们是独立开的。地址只是一个虚拟代号,人为定义的一种管理方式而已,指明数据在什么地方;地址不占用硬件资源。内存是真实存在的物理或虚拟内存,占用硬件资源。_只有为地址绑定了内存,该地址才是有效地址,否则就是野指针。_
1.地址基本概念
1)地址空间 地址空间是程序可使用的地址范围(可寻址范围),是应用程序内部的一种管理机制,虚拟的,不是真实存在的。 2)地址空间范围 X86 CPU包含32位地址线,可寻址范围$2^{32}$,即4GB;X64 CPU包含64位地址线,可寻址范围$2^{64}$即16EB,受系统和硬件限制,实际只实现了$2^{48}$即256TB。 3)地址空间划分
4)地址区域 #一块连续的地址空间
2.内存基本概念
1)物理内存 系统可以使用的实际内存,CPU可以直接访问的内存,真实存在的。 2)虚拟内存 将硬盘文件虚拟成内存使用(C:\pagefile.sys),不是真正的内存。CPU只能访问物理内存,如果要访问虚拟内存数据,必须将虚拟内存数据放到物理内存。 3)内存区域 同地址区域,指一块连续的内存。
3.虚拟内存机制
当用户程序所需的内存超过当前系统可提供的物理内存时,系统会把一部分数据和代码转移到磁盘上,由磁盘文件充当内存,当需要访问这一部分数据或执行某些代码时,再由系统将其转移到物理内存,供CPU访问和执行。 将硬盘文件虚拟成内存使用(C:\pagefile.sys)。 CPU只能访问物理内存,如果要访问虚拟内存数据,必须将虚拟内存数据放到物理内存。 1)从内存获取数据的过程
数据在物理内存还是虚拟内存中,没有规律,只取决于数据使用的频繁程度。 2)页面交换机制 虚拟内存与物理内存进行数据交换。当线程访问某个地址指向的数据时,如果数据在虚拟内存中,系统会把该地址附近(一页)的数据一同交换到物理内存,以此优化内存的使用效率和执行效率。 3)地址转译机制
4.内存分配
关于内存分配这块,我们重点来了解下内存映射文件。它将文件映射成内存,即把硬盘上的文件当内存来用,当用户读写文件映射得到的内存时,就是在读写文件。常用于进程间通信。其主要步骤如下:
- 创建或打开硬盘文件
- 创建内存映射文件
- 加载内存映射文件
- 使用内存
- 卸载内存映射文件
- 关闭内存映射文件
- 关闭文件
最后,我们做个总结: 1.new/malloc 只分配小块内存,有时会有内存空洞 new/malloc在堆上分配内存,分配的内存都是连续的,如图所示,假设分配了两块大小为500M的大内存,两次分配的内存间一般都会有空闲内存,这块内存很有可能因为用户申请大小不合适导致永远不会被使用,即“内存空洞”。 2.大块内存分配和大型结构数组考虑用VirtualAlloc 3.大文件读写考虑用内存映射文件