C++中new[]是否会预留任务管理器未显示的隐形内存?
解答你的内存分配疑问
首先,咱们先拆解你的问题:在VS2017+Win10环境下,执行char* p1 = new char[1073741824];(也就是1GiB的数组分配)时,会不会存在任务管理器/资源监视器没显示的额外内存预留?结合你遇到的bad_alloc错误,我分情况给你讲清楚:
核心前提:32位 vs 64位程序
这是你遇到bad_alloc的关键可能原因,先明确:
- 如果你的程序是32位:Win10下32位程序默认只有2GiB的用户态虚拟地址空间(就算物理内存有4GB也没用)。你已经分配了2GiB,再尝试分配1GiB,虚拟地址空间直接不够,必然抛出
bad_alloc——这种情况下连分配都没成功,自然不存在什么额外内存预留。 - 如果是64位程序:虚拟地址空间大到几乎用不完,这时候才需要考虑内存分配的细节。
标准new操作的内存行为
在VS2017的CRT(C运行时库)中,对于超过512KB的大内存分配,new会直接调用Windows的VirtualAlloc API,而不是用堆分配。默认情况下,这个调用会同时完成虚拟地址空间的预留(Reserve)和物理内存/分页文件的提交(Commit):
- 任务管理器的「已提交内存(Commit Size)」会立刻增加1GiB,这部分是会显示的。
- 「工作集(Working Set)」只有当你实际读写这些内存页时才会逐步增加(因为Win10是按需加载物理内存的),但这不属于“未显示的额外预留”,只是物理内存的延迟分配。
会不会有任务管理器没显示的额外内存?
答案是:标准new操作不会预留请求之外的额外内存,除非有以下特殊情况:
- CRT堆的小分配管理开销:但对于1GiB这么大的块,CRT会绕过堆直接用
VirtualAlloc,这部分管理内存可以忽略不计,不会影响你的分配结果。 - 手动预留未提交的虚拟地址空间:如果你自己调用
VirtualAlloc并指定MEM_RESERVE标记,这时候只是占了虚拟地址空间,没有提交物理内存/分页文件,任务管理器的已提交内存不会显示这部分。但标准new不会这么做,它默认是直接提交的。
你遇到bad_alloc的可能原因(64位程序场景)
如果你的程序是64位,那大概率是虚拟地址空间碎片问题:虽然总虚拟地址空间足够,但找不到连续的1GiB地址块来分配数组(数组需要连续的地址空间)。你可以用微软的VMMap工具查看进程的虚拟地址空间分布,就能清楚看到有没有连续的大内存块可用。
几个排查建议
- 先确认你的项目是64位:VS2017中,右键项目→属性→配置属性→链接器→系统→目标计算机,选择
x64而非x86。 - 用
VirtualAlloc手动测试分配:试试直接调用VirtualAlloc(NULL, 1073741824, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE),如果成功,说明是CRT的new有额外限制;如果失败,就是系统层面的问题(比如虚拟地址碎片)。 - 检查是否有其他内存泄漏:虽然你说预留了4GB物理内存,但如果程序之前分配了很多小内存块导致虚拟地址空间碎片化,也会影响大内存分配。
内容的提问来源于stack exchange,提问作者Jimmy Joe
相关产品推荐
相关产品推荐

