You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C++进程内存映射疑问:堆内存越界访问为何可正常执行?

为什么越界访问堆内存却能正常输出?

先看你给出的这段代码:

#include <iostream>
int main(int argc, char** argv) {
    int* heap_var = new int[1];
    /*
     * Page size 4KB == 4*1024 == 4096
     */
    heap_var[1025] = 1;
    std::cout << heap_var[1025] << std::endl;
    return 0;
}
// Output: 1

你观察到的这个现象,核心和虚拟内存分页机制、堆内存分配器的实际行为这两点有关,咱们一步步拆解:

  • 虚拟内存的整页映射规则:正如注释提到的,操作系统是以固定大小的“页面”(大部分系统是4KB)为单位,把进程的虚拟地址空间映射到物理内存的。哪怕你只通过new申请了4字节(1个int),底层的内存分配器会向操作系统请求整页的内存——因为操作系统不支持分配小于一页的物理内存映射。这就意味着,你的进程实际上拥有了这一整页(4096字节)的合法虚拟内存权限。

  • 堆分配器的额外空间预留:实际的堆分配器(比如glibc的ptmalloc、Windows的HeapAlloc)不会只给你精确的4字节空间。它会在你申请的内存块周围预留一些空间用于管理元数据(比如内存块的大小、是否被占用等),甚至会一次性申请多个连续页面来处理后续的小内存分配请求。你访问的heap_var[1025]对应的地址偏移是1025 * 4 = 4100字节,仅比单页4096字节多4字节,很大概率还在分配器已经为进程申请好的、被映射的虚拟内存范围内。

  • 内存访问错误的触发条件:操作系统只会在你访问未被映射到物理内存的虚拟地址,或者访问的地址没有对应权限(比如写只读页面)时,才会触发段错误(SIGSEGV)或者内存访问异常。在这个例子里,你访问的地址刚好属于进程合法拥有的虚拟内存空间,所以操作系统允许这次读写操作,程序也就正常输出了结果。

⚠️ 重要提醒:这种行为属于C++标准中的未定义行为!这次能正常输出完全是巧合,下次运行可能直接崩溃,或者覆盖其他变量/堆元数据导致难以排查的bug,绝对不要在实际代码中依赖这种行为。


内容的提问来源于stack exchange,提问作者Arnav_Garg

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.21 07:26:19