Windows 8 或者 Windows 10 的任务管理器中,内存已提交的两个数字都是什么意思?

Windows 8 或者 Windows 10 的任务管理器中,内存已提交的两个数字都是什么意思?

木头龙,开了个新专栏,收录些老回答

2020/4/21 更新:之前没找到资料,部分细节不对。


简单理解版

操作系统给应用程序分配内存,打个不那么恰当的比方,就是你上淘宝买东西。

买东西要花钱——运行程序要消耗内存。

你有一个支付宝账户,里面有钱——你的电脑上安装了内存条,叫物理内存。

你开了花呗,可以买东西不花账户里的钱,但是要还可能还要支付利息——操作系统有交换文件,可以暂时存放内存中的数据,但程序要访问这些数据的时候,要把数据读取回内存并且需要更长的访问时间。

你的账户余额和花呗额度加起来,就是你的可消费总额——物理内存容量加上交换文件大小,就是操作系统可以分配给各种程序的内存总额,叫“已提交内存限制”。

你下单了个 5000 块的新手机,这个时候钱虽然没直接给卖家(淘宝会等你收货确认了才打给卖家),但是已经从你的账户或者花呗里面扣掉了 5000,你的消费总额增加了 5000——某个程序向操作系统申请 4GB 内存,虽然可能没真正开始用,但操作系统已经接受并保证应用可以使用的内存总数增加了 4GB。

所以,任务管理器中的“已提交”(Committed)中这两个数字,前面的是操作系统已经接受的应用提交的申请内存容量,后面的是可以接受应用申请的内存容量限制。

深入原理版

这个要从操作系统和应用程序对内存的管理说起。

先说一下计算机里面,现代操作系统是如何管理内存的。物理内存按照字节编号,这个编号称之为地址(Address),地址从 0 开始顺序排序。但除了操作系统内核本身(驱动程序算内核的一部分),其它程序不能直接使用物理地址访问数据。操作系统会向应用程序提供一个连续的虚拟的内存地址空间,当应用程序要访问某个内存数据时,通过这个虚拟的地址访问,而操作系统内核会把这个虚拟地址转换为物理地址后,再进行相应操作。这种内存管理模式叫保护模式,与之相对的则是早期的简单操作系统如 DOS,应用程序直接使用物理地址直接访问内存数据,称之为实模式。实模式的问题在于,如果一个程序发生错误,使用了一个错误的地址并改写了其中的数据,如果这个地址是其它程序使用的,会导致其它程序出错;更严重的情况是这个地址是操作系统使用的,可能会导致系统崩溃。甚至某些恶意程序如病毒木马,可以访问并窃取其它程序的机密数据。

在保护模式中,操作系统向应用程序提供的虚拟地址是连续的,但对应的物理地址则通常是随机并且错乱的。例如一个虚拟内存地址空间大小为 M,内核保留地址空间大小为 N 的操作系统,使用容量为 X 的物理内存,运行一个应用程序 A:

没有颜色的是未使用的内存

图中“应用程序”用“进程”(Process)来表示。因为一个应用程序运行的时候可能会有多个进程,每个进程都有自己独立的虚拟地址空间。

补充一下,上图中的 M 和 N 对于特定的操作系统是固定的,例如 32 位 Windows,M 就是 2³²=4GiB,N 是 M 的一半,2GiB(通过特殊的启动参数可以改成 3GiB);64 位 Windows,M 是 2⁶⁴=16EiB,N 是 8TiB[1]

接着运行另外一个进程 B,而且进程 A 没有退出释放内存,可能会变成这样:

可以看到,两个进程都有自己独立的虚拟地址空间,相同地址的虚拟内存会被映射到不同的物理内存上,互不干扰。但内核使用的物理内存只有一份,映射到不同进程的虚拟地址空间中,因此称之为“池”(Pool)。

我们需要一张映射表来记录虚拟内存和物理内存的映射关系(图中的箭头)。如果每个内存地址都需要一条记录,显然很浪费也没必要,现代 PC 中以页(Page)为单位,每一页大小为 4096 字节(4KiB),映射表只记录虚拟内存页到物理内存页的映射关系。

PS:并非所有内存都可以分页的,操作系统内核以及驱动程序使用的一部分内存是不能分页的(例如处理分页错误有关的代码),这部分内存的大小就是任务管理器中的“非分页池”(Non-Paged Pool,不清楚中文版的 Windows 为什么加入“缓冲”叫“非页面缓冲池”)。话说我很好奇题主装了用什么硬件或者做了什么设置,这部分竟然使用了 5.8GB 内存,一般非分页池只会使用几百兆左右。

内核使用的其它内存,则可以分页使用,就是“分页池”(Paged Pool,中文版 Windows 界面显示的“页面缓冲池”)[2]

有了映射表,就可以实现一种特殊的内存使用方式——页面交换。假设继续运行另外一个进程 C,进程 C 需要使用大量的内存。这个时候就会变成这样:

操作系统会在硬盘上使用一个(也可以是多个)特殊的文件,称之为交换文件(Swap file)或者分页文件(Paging file),把暂时不用的物理内存页面中的数据写入这个文件,释放出来的页面用来存放进程 C 的数据。上图中,原来进程 A 使用的页面 6 被交换到地址 X,进程 B 使用的页面 5 被交换到地址 X+1。页面 5、6 用于存放进程 C 的数据,页面 X、X+1 为交换文件中的页面。

很显然,对于操作系统来说,可用的内存页面数量为 X+1,总容量超过了物理内存大小。也就是说,操作系统可以使用比物理内存容量更大的内存。代价则是当进程 A 需要访问虚拟地址空间中第 3 个页面中的数据时,需要从硬盘上的交换文件,把页面 X 交换回物理内存中,这个时间比直接访问内存慢很多。例如今天的主流电脑访问内存延迟一般是 50~100 纳秒,访问固态硬盘的延迟一般是数十微秒——慢几百上千倍,访问机械硬盘的延迟一般是十多毫秒——慢几十万倍。

在第三张图中,可用内存容量为 X+2,其中 X 为物理内存容量,2 为交换文件大小。任务管理器中“已提交内存”后面的数字就是可用内存容量。顺道说一下,上面提到的“非页面缓冲池”所使用的内存,因为不能分页,所以是不可以交换到页面文件上的;而“页面缓冲池”使用的内存,可以和普通程序的页面一样,在长时间不使用时交换到页面文件上,腾出内存空间给其它应用使用。

当进程向操作系统请求使用一段内存的时候(例如 C 语言中调用 malloc 函数),就 Windows 来说,是调用 VitualAlloc API。根据调用的参数不同,会有两种处理方式[3]

  • MEM_RESERVE,请求并保留。Windows 会在虚拟内存中按照请求的内存地址和数量分配页面,并保证这部分虚拟内存在将来可用,不会被其它操作占用。但对物理内存、交换文件都没有任何影响。
  • MEM_COMMIT,请求并提交。Windows 会根据请求的内存数量相应增大已提交内存数量,保证将来进程使用这部分内存的时候有足够的内存资源分配给进程。但直到进程真正访问对应的内存时,操作系统才会在物理内存中给应用程序分配内存页面并且初始化。此外,请求的虚拟内存起始地址以及数量所描述的内存段必须先通过 MEM_RESERVE 方式的 VirtualAlloc 调用所保留,否则会报错。

可以把两个参数进行 OR 运算后传入,一步调用就保留并提交。

任务管理器中“已提交”的两个数字,前面的数字,就是所有进程请求并提交的内存数量总和。这个值不能超过可提交内存上限,也就是后面的数字。可提交内存上限是物理内存容量 + 交换文件大小 - 内核保留内存。

如果进程试图向未提交的虚拟内存地址写入数据,会引发异常,例如这样:

这样的错误提示估计很多人都见过吧?

如果进程申请提交的内存数量加上已提交的内存数量超过了可提交内存上限,则会引发虚拟内存不足异常:

不过 Windows 默认由操作系统管理分页文件(这里用 Windows 界面上的用词)大小,如果可提交内存上限不足,Windows 会自动扩大分页文件大小,增大可提交内存上限。所以除非硬盘也满了,否则很少会出现这个错误,但如果有的朋友自己设置了分页文件的最大值而且设置的值不够大,则有可能碰到这个错误。此外,扩大分页文件是磁盘操作,相对内存操作来说速度很慢,有可能因为超时导致应用程序出错。其它操作系统的交换文件大小一般是固定的(例如 Linux),需要手动调整。

前面说了使用分页文件很慢,那是否物理内存足够大我们就可以禁用分页文件呢?也不是。因为很多程序会提交一大段内存,但仅仅使用了其中一部分。像虚拟机、Ramdisk 这类软件,根据设置可能动则申请数 GB 内存,但实际只用了其中几百兆。假设我们运行一台内存设置为 8GB 的虚拟机,但实际上虚拟机只使用了 500MB 内存,如果禁用了交换文件,那么操作系统就必须在物理内存中保留 8GB 空间给虚拟机进程;如果分页文件设置为 2GB,操作系统就必须在物理内存中保留最少 6GB 空间;如果分页文件设置为 8GB,那么只有虚拟机进程使用的 500MB 是真正占用了物理内存的。剩余的 7.5GB 只使用了页面文件所提供的可提交内存容量。

下图中,已提交比已使用内存要大 6.8G,就是这部分被占用但未使用的内存(运行着一台 2GB 内存的虚拟机,一个 2GB 大小的 Ramdisk)。

如果要自行设置分页文件大小的话,建议先正常使用一段时间,在任务管理器中观察“已使用”和“已提交”的差值,多观察几次后,把分页文件的最小值设置为比这个差值常见大小稍大一点,这样可以最有效的利用内存和硬盘容量——毕竟现在的固态硬盘也不便宜,分页文件的最小值设置太大也是一种浪费;反过来,内存价格更贵,页面文件设置太小导致内存容量白白被占着不用更浪费——例如这个问题下的 @波心荡 朋友三年前的回答。

补充一下:这种设置分页文件的方式并未考虑物理内存不足需要使用页面文件的情况,所以和很多网上使用技巧所推荐的分页文件设置为物理内存大小的 1.5 倍(或者类似的其他值)不同。毕竟电脑的使用场景太多了,内存大小配置也有很多情况。很可能你平时就上个网追个剧,8G 内存绰绰有余;但写毕设论文的时候大型软件开着两三个;到处找资料网页窗口就开着几十个;还要开个 Photoshop 来画图说明——这个时候要是你按照上面说的就设置了 2GB 分页文件,肯定是不够用的。