Linux下VmPeak和VmSize仅反映已用虚拟内存,非地址空间上限;真实上限由RLIMIT_AS软限制(/proc/self/limits中Max address space)、mmap_base位置及x86_64架构用户空间128TiB理论值共同决定。

Linux 下用 /proc/self/status 查看 VmPeak 和 VmSize 不代表地址空间上限
很多人误以为读取 /proc/self/status 中的 VmPeak(峰值虚拟内存)或 VmSize(当前虚拟内存大小)就能知道“可用虚拟地址空间上限”,其实不是。这两个值反映的是进程**已使用**的虚拟内存统计,和系统允许分配的**最大地址范围**无关。真正的上限由 CPU 架构、内核配置和进程地址空间布局决定。
64 位 Linux 上实际可用虚拟地址空间取决于 mmap 区域起始位置和 RLIMIT_AS
在 x86_64 Linux 中,用户态虚拟地址空间通常被划分为低地址的堆/栈/mmap 区和高地址的内核空间(如 0xffff800000000000 起)。真正能用于 mmap 分配的连续用户空间上限,取决于:
- 当前 mm->mmap_base(由内核 ASLR 决定,可通过 /proc/self/maps 第一行非固定映射的地址估算)
- getrlimit(RLIMIT_AS, &rlim) 返回的软限制(单位字节),它会直接限制 mmap 可申请总量
- 内核编译参数:比如是否启用 CONFIG_ARM64_VA_BITS_52 或 CONFIG_X86_PAE,但普通用户无法绕过 RLIMIT_AS 的硬约束
实操建议:
- 调用
getrlimit(RLIMIT_AS, &rlim)获取当前软/硬限制;若软限制为RLIM_INFINITY,说明没被显式设限,此时可认为上限由架构决定(如 x86_64 用户空间理论为 128 TiB,但实际mmap_base往往在 ~47 位地址处) - 检查
/proc/self/maps中第一个mmap区域起始地址(如7f...000),它大致指示了用户空间上界下沿 —— 地址再往上可能已被保留或不可映射 - 不要依赖
sysconf(_SC_PHYS_PAGES)或sysconf(_SC_AVPHYS_PAGES),它们返回的是物理内存页数,和虚拟地址空间完全无关
Windows 上需用 GetSystemInfo 结合 IsWow64Process 判断真实用户空间范围
Windows 的用户态地址空间上限更依赖运行模式:
- 32 位进程(无论系统是 32 还是 64 位):默认上限 2 GiB;若启用
/LARGEADDRESSAWARE且系统开启bootcfg /set {current} increaseuserva 3072,可达 3 GiB - 64 位进程:理论 8 TiB 用户空间(
0x0000000000000000–0x00007FFFFFFFFFFF),但实际可用取决于SYSTEM_INFO.lpMaximumApplicationAddress - 必须先用
IsWow64Process(GetCurrentProcess(), &isWow64)确认是否为 WoW64 进程,否则GetSystemInfo返回的lpMaximumApplicationAddress可能是 32 位视图
关键代码片段:
组合式C++代码评审方案,融合静态分析、AI推理、多轮迭代评审和C++专项检查,适用于PR审查、增量代码审查、全项目评审和代码质量评分,触发词包括review cpp、cpp代码评审、C++review、代码审查。
立即学习“C++免费学习笔记(深入)”;
SYSTEM_INFO si;
GetSystemInfo(&si);
printf("Max app addr: %p\n", si.lpMaximumApplicationAddress);
跨平台没有统一 API,std::numeric_limits<uintptr_t>::max() 是误导性答案
有人直接返回 std::numeric_limits<uintptr_t>::max(),这是错的 —— 它只表示指针能编码的最大整数值,并不等于操作系统允许进程使用的最大虚拟地址。例如在 x86_64 Linux 上,uintptr_t 是 64 位,但内核通常只暴露 48 位(256 TiB)或 57 位(128 PiB)给用户空间,且其中还包含空洞、保留区、栈/堆冲突区。
真正可靠的做法是:按平台分别查 RLIMIT_AS(POSIX)或 GetSystemInfo(Windows),并接受“上限”本身是个动态、分段、受多层策略控制的值,不是单个数字能概括的。最容易被忽略的是:即使地址空间足够,mmap 仍可能因 ENOMEM 失败 —— 原因常是 RLIMIT_AS 耗尽,而非地址越界。

















