ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Windows虚拟内存与分页文件:从原理到OOM排查的完整指南

Windows虚拟内存与分页文件:从原理到OOM排查的完整指南 编译到一半Visual Studio 突然弹出“系统内存不足”浏览器开了四十多个标签页切个窗口卡得鼠标都要漂移新起的测试服务刚启动就被 OOM 干掉——这几个场景大部分人第一反应是赶紧加内存条。但有个反直觉的事实是物理内存加得再大Windows 照样可能弹“内存不足”。原因就藏在虚拟内存这个被无数人误解的机制里。这篇文章我会把 Windows 虚拟内存分页文件的原理、故障判断、参数设置以及开发机上 Elasticsearch、MySQL、Docker 一类应用出现 OOM 时的真实处理思路完整梳理一遍。适合普通用户、开发者也适合偶尔要接手 Windows 服务器的人。整篇没有晦涩的理论堆砌所有内容都来自实际踩坑和验证。1. 分页文件在 Windows 内存体系里的真实角色先想清楚它到底解决什么问题1.1 虚拟内存的本质物理内存不足时的“溢出区”先把术语对齐。Windows 里的“虚拟内存”日常指的就是那个叫pagefile.sys的文件默认放在系统盘根目录也被称为分页文件、页面文件。它的作用是当物理内存不够用的时候把暂时不用的内存数据挪到磁盘上暂存等需要时再换回来。很多人以为虚拟内存是“假内存”其实更准确的比喻是物理内存是你的工位抽屉分页文件是楼下仓库。抽屉满了把暂时不用的文件和材料放到仓库等要用的时候再去取。仓库不会替代抽屉但它能让你的工位在有限空间内处理更多事情。从 Windows 内部视角看分页文件的作用比这个比喻还要深入一层。现代操作系统给每个进程都分配了一个独立的虚拟地址空间64 位进程理论上可以寻址极大范围的内存地址。进程申请内存时系统先“承诺”给它一块地址空间这部分暂时不落地等进程真正读写时再由物理内存或分页文件来承接。这里就引出一个关键点分页文件不是等物理内存用完了才出现它是整个内存管理体系的一部分负责承接那些“被承诺但未在物理内存中落地”的页面。在极端情况下哪怕物理内存还有空闲如果分页文件设置得太小系统也可能因为无法继续提供可提交的地址空间而拒绝分配内存这就是很多“明明内存够用却报内存不足”场景的来源。1.2 为什么“内存大就不用虚拟内存”这个想法是错的我见过不下十个人在 16G、32G 内存的机器上把虚拟内存一关觉得这样能“释放磁盘空间、提高性能”。短时间看着是没事但一旦打开大型游戏、跑虚拟机、编译大型工程问题就接踵而至。第一个问题是提交量Commit Charge。Windows 的任务管理器里有一项“已提交”表示整个系统所有进程已经向操作系统申请的内存承诺总量。这个量可以超过物理内存因为它只是“承诺”不代表马上全部占用。系统允许的承诺上限也就是“提交限制”大致等于物理内存大小加上全部分页文件的和。如果把分页文件设为无提交限制就等于物理内存大小。于是即使物理内存还剩 30%只要有程序申请了大量虚拟地址空间游戏加载、JVM 启动、编译器符号表就可能直接顶到提交限制导致应用启动失败或者系统弹窗提示内存不足。第二个问题是崩溃转储。Windows 在蓝屏或者系统崩溃时需要把内存中的调试信息写到磁盘上默认路径就在系统盘的页面文件中。如果完全禁用分页文件系统崩溃时就无法保存 dump 文件排错就少了一条非常重要的线索。我自己排查过几次蓝屏问题都是靠 C 盘的 pagefile 里保留的 minidump 才定位到具体驱动。完全禁用的机器遇到蓝屏基本只能靠猜。第三个问题是某些老软件和驱动对分页文件有硬依赖。十年前的一些 32 位程序、老版本杀软或者特殊设备驱动在系统完全没有 pagefile 时会直接拒绝工作或者行为异常。现在虽然少了但在企业环境里偶尔还会碰到。所以我在任何情况下都不建议完全禁用虚拟内存。物理内存再大至少保留一个由系统托管的小页面文件就对了。2. 从“内存不足”弹窗到 OOM 崩溃怎么读懂这些报警信号2.1 各种内存不足的报错讲的其实不是同一件事Windows 的“内存不足”报错背后可能是完全不同的原因。最常见的一种是系统托盘弹出“内存不足请关闭部分程序”同时任务管理器里物理内存占用非常高。这种情况确实是物理内存吃紧程序申请不到足够的物理页面系统只能靠频繁换页硬撑。处理手段是关闭大内存应用或者加内存条。第二种是应用自身报 OOM比如 Java 程序直接抛java.lang.OutOfMemoryError浏览器显示“页面崩溃”或者游戏弹出“显存不足”。这些要分开看Java OOM 一般是 JVM 堆内存分配不到连续地址空间或堆大小不够浏览器崩溃可能是因为单个标签页进程占满用户态地址空间显存不足更是和虚拟内存毫无关系——任务管理器里那个“共享 GPU 内存”是显卡驱动从系统物理内存划给 GPU 用的一块区域不是分页文件。第三种是系统级警告事件查看器里能看到 Event ID 2004 或 2020内容大意是“Windows 已检测到虚拟内存不足以下程序占用了大量内存”。这种事件出现说明系统提交限制接近耗尽需要特别注意。区分这几种情况是排错的第一步。如果听到“OOM”就急着去改虚拟内存方向可能完全跑偏。2.2 用作用域“已提交”和“提交限制”快速定位根因排在 Windows 内存问题最实用的工具就是任务管理器。打开“性能”页选中“内存”能看到一组关键数据“使用中”物理内存已经被进程和数据占用的部分。“已提交”和“提交限制”两者组成的数值比如“12.5/31.9 GB”就是整个系统当前提交量与允许的最大提交量。我的判断逻辑是这样的现象主要问题优先处理方向已提交接近提交限制超过90%但物理内存使用率一般系统提交地址空间不足pagefile 太小增大分页文件或增加物理内存物理内存使用率长期90%以上已提交离限制还很远物理内存容量不足关闭大内存应用或加内存条应用启动即失败报内存不足但物理内存还有大量空闲提交限制被顶满通常是 pagefile 被禁用或过小恢复/扩大 pagefile单个进程崩溃系统层面无异常进程自身堆内存或地址空间问题查应用日志调整该进程内存参数命令行里也可以快速看分页文件的实际使用情况wmic pagefile list /format:list需要看当前用量、峰值用量和分配大小的话用 PowerShellGet-CimInstance Win32_PageFileUsage | Select Name, AllocatedBaseSize, CurrentUsage, PeakUsage我举一个实际遇到过的例子一台 16G 内存的机器装了 Docker Desktop、几个 IDEA 项目、再加 Chrome 常驻用户反映经常“内存不足”。我远程一看任务管理器里物理内存才用了大概 9G但已提交已经 14.8G提交限制刚好 16G。这就是典型的 pagefile 被手动设为 0 导致的问题。恢复 C 盘系统托管分页文件之后提交限制变成约 24G问题再没出现过。2.3 分页文件与蓝屏转储容易被忽略的“案发现场”提到 Blue Screen这里多说一句。Windows 崩溃时核心的内存快照可以选择写入分页文件重启后系统再把 dump 提取出来保存。这个机制要求系统盘上必须存在一定大小的页面文件。如果你把 pagefile 完全禁掉系统崩溃后就没有任何现场记录windbg 根本无从分析。所以哪怕你决定把主要的虚拟内存放到其他盘也建议在 C 盘保留一个系统托管或者固定小值比如 512MB~1GB的页面文件。这样既不影响磁盘空间又能在关键时刻留下诊断数据。这个小习惯在后端开发机上尤其重要。3. 虚拟内存大小不要拍脑袋内存容量、硬盘类型和用途决定参数3.1 老的 1.5 倍 / 3 倍公式为什么不再靠谱网上流传最广的“虚拟内存设为物理内存的 1.5 倍最大 3 倍”在当年 128M、256M 内存年代有一定道理。那时的系统对内存的需求几乎是“给多少吃多少”物理内存太小pagefile 必须足够大才能兜底。但现在 16G、32G 内存已经是常态再按 3 倍去设32G 内存就要建一个接近 100G 的分页文件。等你看到 C 盘被一个几十上百 GB 的 pagefile.sys 占满就知道这个公式有多离谱了。更关键的是系统日常根本用不到这么大完全是在浪费磁盘空间。现代 Windows 的默认策略是“自动管理所有驱动器的分页文件大小”。系统会根据物理内存容量、当前负载和磁盘剩余空间动态调整 pagefile 大小。对大多数普通用户这个默认设置已经足够好不需要手动干预。手动设置真正有意义的是三类场景一是开发机和服务器需要性能稳定避免系统在负载高峰时自动扩展 pagefile 带来的 IO 抖动二是需要保留崩溃 dump 的生产环境必须确保系统盘有足够的页面文件空间三是某些第三方软件与自动管理有兼容问题需要固定大小来规避。3.2 不同内存容量下的推荐配置下面这组配置是我在各种机器上反复验证过的可以作为起点再根据具体负载微调。物理内存适用场景初始大小最大值备注8GB办公、网页、轻度开发4096 MB8192 MB游戏或虚拟机场景建议手动固定8GB日常轻度使用系统托管系统托管省心16GB浏览器多开、IDE、轻度虚拟化系统托管系统托管若频繁编译可固定 8192-12288 MB16GB多虚拟机、大型 IDE 项目8192 MB16384 MB固定大小减少动态扩展抖动32GB普通使用系统托管系统托管通常默认就很稳32GB大型编译、容器环境、开发服务器8192 MB16384 MB不需要超过物理内存一半太多64GB以上绝大多数场景系统托管系统托管只需在系统盘保留小页面文件用于 dump这里补一个容易踩的误区把最大值设得特别大并不会让系统“变快”反而会给人一种“内存不够没关系反正有虚拟内存兜底”的错觉让进程持续累积内存占用而不释放。虚拟内存再大磁盘 IO 的物理瓶颈摆在那里频繁换页时系统一样卡成幻灯片。它的定位是缓解和兜底不是根治。3.3 SSD 和机械盘虚拟内存放哪里更好不少人对“在 SSD 上设置虚拟内存会不会伤盘”有顾虑。从实际写入量看这个担心是多余的。分页文件并不是一直在高速写入只有物理内存压力大的时候才频繁换页。日常使用下它的写入量相比系统更新、浏览器缓存、日志写入占比非常小。现代 SSD 的寿命足够扛住这种负载。真正需要注意的是性能分布分页文件应该放在读写速度最快的盘上也就是系统 SSD而不是为了“给 SSD 减负”把它挪到机械盘。机械盘的随机读写速度只有 SSD 的几十分之一一旦系统真的发生换页机械盘会直接成为性能瓶颈卡到你怀疑人生。如果机器上有多个 SSD也没必要把 pagefile 拆到多块盘上。分散到多盘并不会带来可感知的性能提升反而会增大配置复杂度出现问题后还不好排查。老老实实放在系统盘或者单独一块高性能 SSD 上就够了。4. Windows 10 / 11 实操从查看当前配置到完成设置4.1 先搞清楚当前状态再动手调整之前先确认两件事当前的分页文件配置以及系统有没有提交压力。打开任务管理器切到“性能”页点“内存”看“已提交”和“提交限制”。如果已提交占提交限制的比例在 80% 以下说明系统提交空间充足不需要大改如果经常会到 90% 以上才需要介入。然后看当前配置右键“此电脑”Win11 是“此电脑”没改名→“属性”→“高级系统设置”在“高级”标签页的“性能”区域点“设置”再切到“高级”“虚拟内存”区域点“更改”。这里就能看到哪个盘分配了页面文件大小是多少以及管理方式。命令行确认更直观wmic pagefile list /format:list输出里AllocatedBaseSize是当前分配的初始值CurrentUsage是当前实际占用的 MB 数。如果CurrentUsage长时间接近AllocatedBaseSize说明分页文件可能需要增大如果始终只有几百 MB说明系统压力不大保持现状即可。4.2 完整设置步骤与分盘建议确认完现状开始正式调整。以 Windows 11 为例步骤和 Win10 基本一致在“虚拟内存”设置窗口里先取消勾选“自动管理所有驱动器的分页文件大小”。选中需要设置页面文件的盘符一般选 C 盘或一块 SSD。选择“自定义大小”输入“初始大小”和“最大值”点击右边的“设置”按钮。注意必须先点“设置”直接点“确定”配置不会生效。如果想另起其他盘存放先选中目标盘符重复第 3 步。同时建议保留系统盘上一个小页面文件大小为 512MB~2048MB用于内存转储。点“确定”系统会提示重启保存所有工作后重启一次。修改分页文件后必须重启才能生效。不重启就继续用容易看到 win11 虚拟内存配置错误之类的提示。“初始大小”和“最大值”是否要设为同一个数值我倾向于建议开发机和服务器设为相同值即“固定大小”。这样系统不会在运行过程中动态扩展文件减少了磁盘碎片和 IO 抖动行为也更可预期。普通办公娱乐机器直接交给系统托管最省心。4.3 设置完一定要做的验证和常见异常重启之后按前面的方法再看一遍任务管理器“提交限制”是否变成了预期数值。理论上它会约等于物理内存总大小加上所有分页文件大小。用wmic pagefile list /format:list查看AllocatedBaseSize是否和配置的一致。事件查看器里打开“Windows 日志”→“系统”看几分钟内有没有新的 Event 2004 或 2020。如果没有说明提交压力暂时缓解。实操中我碰到过的异常主要有这么几个第一按钮灰色点不动。最常见原因是“自动管理所有驱动器的分页文件大小”没有取消或者当前账户不是管理员。用管理员身份运行设置程序即可。第二设置后提示“磁盘空间不足”。分页文件需要连续磁盘空间如果 C 盘快满了即使剩余的零散空间够大系统也可能拒绝创建。先清理磁盘或者把页面文件放到其他盘。第三Win11 上改了配置但重启后恢复原样。这种情况多半是系统优化工具或安全软件把注册表里的相关配置又改回来了。检查一下有没有装“内存优化”“系统清理”类的工具将其排除项里加入分页文件相关设置或者卸载这些第三方工具。第四分页文件明明设了 8G但系统显示只用了 1G 多。这其实是正常现象。固定大小只是上限系统用不到那么多时物理文件不会立即扩展到设定值而是在真正需要时再增长。只要提交限制显示正确就说明配置已经生效。5. 开发机上的 OOM 复盘Elasticsearch、MySQL、Kafka 与 Docker 的真实处理思路5.1 Elasticsearch OOM先查 JVM 堆别急着加虚拟内存很多团队喜欢在 Windows 笔记本上起一个 Elasticsearch 做本地开发。装好之后一跑过几分钟就报 OOM。看一眼日志大部分是java.lang.OutOfMemoryError: Java heap space少数是native memory或unable to create native thread。Heap space 的直接解法是调整jvm.options里的Xms和Xmx。开发环境建议两个值设成一致避免运行时动态扩堆带来的停顿。物理内存 32G 的机器ES 堆设 8G 已经够测试16G 内存的机器堆设 4G 比较稳。注意不要超过物理内存的一半ES 不只是用堆它还需要大量堆外内存和操作系统页缓存。unable to create native thread这类错误则要复杂一些。JVM 创建线程需要系统分配线程栈空间如果整机“已提交”接近提交限制即使物理内存还有剩余线程也可能创建失败。这种时候调整 pagefile 是有效的因为提升提交限制能给 JVM 更多创建线程的余量。但长期看还是得减少进程数量或者增加物理内存。另外强调一点Windows 上跑 ES 不需要像 Linux 那样关心max_map_count但一样要关注物理内存余量和磁盘 IO。ES 的索引写入和查询非常吃磁盘分页文件如果放在机械盘上一旦发生换页整个 ES 会卡到无法服务调再大的堆都没用。5.2 MySQL、Kafka 在 Windows 上的内存调优思路MySQL 在 Windows 上 OOM我见过最多的原因不是 Windows 虚拟内存设置不当而是innodb_buffer_pool_size配置得不合理。默认情况下 MySQL 的 buffer pool 比较保守只有 128M 左右。有人为了提高性能直接把它调到 8G、12G但机器总共才 16G 内存。平时空闲还好一旦并发查询上来内存被 buffer pool 占满再加上连接缓冲、排序缓冲、临时表物理内存立刻告急系统只能靠 pagefile 硬换页最终整个数据库卡死。合理的做法是把innodb_buffer_pool_size设成物理内存的 50%~70%同时留出至少 2G~4G 给操作系统和其他进程。如果 MySQL 所在主机还跑着 Java 应用、Docker 之类这个比例还要再往下压。切忌把内存参数按“最大理论值”来设。Kafka 是另一个容易被误会的组件。它本身是 JVM 应用堆内存由KAFKA_HEAP_OPTS控制但它的核心优势又依赖操作系统的 page cache 来缓存消息数据。也就是说堆内存不能给太大要给系统留出足够物理内存来做页缓存。在 Windows 开发机上跑 Kafka如果整机内存紧张先看任务管理器里物理内存是不是被堆耗光了而不是先怀疑 pagefile 设置。这类中间件的 OOM 排查顺序我建议统一为进程自身内存参数 → 物理内存容量 → 系统提交限制 → pagefile 大小。顺序不能乱大多数情况在前两步就能定位问题盲目扩大 pagefile 只是掩耳盗铃。5.3 Docker Desktop 和 WSL2虚拟内存之外还有一层“虚拟机”Windows 上的 Docker Desktop 默认走 WSL2 后端容器跑在一个轻量虚拟机上。这个虚拟机有自己独立的内存上限和 Windows 宿主机的 pagefile 不是一个概念。我接过一个同事的反馈Docker 里跑了个 MySQL 容器数据量稍微大一点容器就被杀docker stats里内存直接顶满。查了半天不是 VM 里的虚拟内存问题而是 WSL2 虚拟机分到的内存总额不够。Windows 宿主机内存 16G但.wslconfig里被某个旧教程设成了memory4GB容器当然不够用。解决办法是修改用户主目录下的.wslconfig比如[wsl2] memory8GB processors4 swap2GB保存后执行wsl --shutdown再重新打开 Docker Desktop 即可生效。这里特别提醒swap不要设置为 0。WSL2 默认会创建一个 swap 文件作为虚拟机自身的交换空间。如果设为 0容器瞬间申请大量内存时没有缓冲容易被直接 OOM Killed。除非你非常确定 WSL2 的峰值内存远低于分配内存否则不建议关掉它。排查时怎么区分是宿主机问题还是 WSL2 虚拟机问题在 WSL 终端里执行free -h看可用内存和 swap 用量用dmesg | tail -n 50看有没有Out of memory或者Killed process的日志。如果日志里有明显的 OOM Killed 记录说明是 WSL2 虚拟机内部的内存上限被顶满了这时候去调 Windows 的 pagefile 基本没用正确做法是调整.wslconfig或者减少容器并发。另外Docker Desktop 本身在“Settings → Resources”里也可以调整内存和 swap 上限图形界面操作更直观。WSL2 和 Docker Desktop 的内存配置叠加生效先看清是哪一层在限制你再动手改。最后说一句实在话。我在这几年里折腾过不少 Windows 机器的虚拟内存也看过很多人把中间件 OOM 全部归咎于 pagefile 太小。实际上绝大多数应用层 OOM最后都是靠调整进程自己的堆内存、缓冲池和容器限制解决的。pagefile 真正应该承担的角色是给系统在提交压力瞬间一个缓冲并在崩溃时留下现场数据。把这一点想明白再动手去配基本不会出大错。
返回列表