为什么64位Windows系统无法分配大容量虚拟内存?
问题描述
在支持虚拟内存的系统上,理论上可分配远超物理RAM容量的地址空间,仅在实际写入数据时才会占用物理内存。
32位系统的虚拟地址空间上限为4GB,该限制在64位系统上本应不存在。
尽管Windows未使用完整64位地址空间,目前仅用44位,对应容量仍达16TB,因此分配1TB地址空间理应无问题。
为此我编写了测试程序,尝试以每次10GB的粒度分配1TB地址空间,代码如下:
#include <new> #include <stdio.h> void main() { std::set_new_handler([]() { perror("new"); exit(1); }); for (int i = 0; i < 100; i++) { auto p = new char[10ULL << 30]; printf("%p\n", p); } }
该程序在配备32GB RAM的Windows x64系统上运行,得到如下结果(每次运行的具体地址有差异,但整体表现一致):
0000013C881C1040 0000013F081D0040 00000141881E2040 00000144081F1040 0000014688200040 0000014908219040 0000014B88226040 0000014E08232040 0000015088246040 0000015308252040 0000015588260040 new: Not enough space
程序仅成功分配110GB就报错退出,该容量虽大于物理RAM,但远低于理论可用地址空间上限。
可以确认程序并未对分配的内存执行写入操作(写入操作需要分配物理内存,我测试过分配后立即调用memset写入,程序运行速度会明显变慢,符合预期)。
请问该虚拟内存分配限制的来源是什么?
问题解答
核心原因是标准C++的new操作符在Windows平台的默认行为和预期不一致:它会同时完成地址空间保留和内存页提交两个动作,而非仅保留地址空间,因此分配量会受到系统*提交限制(Commit Charge Limit)*的约束,这个限制的总大小等于物理内存容量 + 系统配置的页面文件总容量。
- 测试机物理内存为32GB,按测得的110GB分配上限推算,当前系统的页面文件总大小约为70~80GB,两者相加刚好和测试结果吻合。
- 提交限制是Windows的内存保障机制:所有已提交的内存,不管用户有没有写入数据,系统都会预留对应的后备存储(物理内存或页面文件空间),确保后续写入操作不会因为没有存储资源失败,因此总提交量永远不能突破物理内存+页面文件的总大小,和用户是否写入没有关系。
如果要单独测试地址空间的分配上限,不要使用标准new,直接调用Windows原生API VirtualAlloc,仅指定MEM_RESERVE标志,这个操作只会占用进程的地址空间,不会计入提交计数,就能分配到接近16TB的地址空间,符合理论上限。
内容的提问来源于stack exchange,提问作者rwallace
相关产品推荐
相关产品推荐

