VMPeak字段记录进程自启动以来虚拟内存历史最大值(单位KB),包含mmap、brk等所有虚拟地址空间,fork后重置,不可清零;硬限制需用getrlimit(RLIMIT_AS)获取字节级值,非/proc/self/limits显示值。

Linux下用/proc/self/status读取VMSize和VMPeak
Linux进程的虚拟内存峰值(即历史最大RSS+未映射但已分配的虚拟地址空间)实际记录在/proc/self/status的VMPeak字段,单位是KB;VmSize是当前虚拟内存总大小。这不是实时采样值,而是自进程启动以来达到过的最大值,内核自动维护,无需额外触发。
直接读取即可,注意权限和时机:子进程fork后该值重置,多线程不干扰。示例代码片段:
std::ifstream proc("/proc/self/status");
std::string line;
while (std::getline(proc, line)) {
if (line.rfind("VmPeak:", 0) == 0) {
std::istringstream iss(line.substr(7));
long peak_kb = 0;
iss >> peak_kb;
// peak_kb 即为峰值KB值
break;
}
}
-
VMPeak包含所有mmap、brk、stack、vvar/vdso等虚拟地址空间,比cat /proc/pid/status看到的更全 - 若程序刚启动就立即读,可能返回0或极小值——需在内存分配密集操作(如加载大模型、解析大文件)之后读取才有效
- 该值不可重置,也无法通过系统调用清零;重启进程是唯一归零方式
硬限制靠getrlimit(RLIMIT_AS)而非/proc
虚拟内存硬限制(address space limit)由RLIMIT_AS控制,不是/proc/self/limits里“Max address space”那一行的显示值——那是格式化后的字符串,易受locale影响且不可靠。必须用getrlimit()系统调用获取原始rlimit_t值。
注意:RLIMIT_AS限制的是进程可分配的**虚拟地址空间总量**(包括mmap、malloc、stack等),不是物理内存,也不等于VMPeak。当malloc/mmap超出此限时会直接失败(errno=ENOMEM)。
立即学习“C++免费学习笔记(深入)”;
- 调用
getrlimit(RLIMIT_AS, &rlim)后,rlim.rlim_cur是当前软限,rlim.rlim_max是硬限(单位:字节) - 普通用户无法提升硬限,除非以root运行并先调用
setrlimit() - 某些容器环境(如Docker)会通过cgroup v1的
memory.limit_in_bytes间接影响RLIMIT_AS,但机制不同,不能混为一谈
统计报告建议组合/proc/self/statm与mallinfo()
单一指标不够反映内存行为。真实调试需要交叉验证:/proc/self/statm提供页数级粗粒度(size、resident、shared),而mallinfo()(glibc)给出堆分配器内部状态(uordblks、fordblks等)。两者互补,但有局限。
-
/proc/self/statm第一页数是size(总程序大小,含代码段),第二页是resident(当前驻留物理页),单位是内存页(通常4KB)——它不含swap-in/out抖动细节 -
mallinfo()只统计malloc/free系分配,不包含mmap(MAP_ANONYMOUS)或new(除非libstdc++底层用了malloc) - 推荐在关键路径前后各采一次,计算差值;避免高频轮询——
/proc读取有轻微开销,mallinfo()在多线程下非原子,glibc 2.35+已标记为deprecated
Windows平台没有等价的VMPeak,得用GetProcessMemoryInfo
Windows没有内核维护的“历史虚拟内存峰值”字段。PROCESS_MEMORY_COUNTERS_EX结构体中PeakPagefileUsage和PeakWorkingSetSize分别对应换页文件峰值和工作集峰值,但都不是虚拟地址空间峰值(VMPeak)。真正接近的是PrivateUsage的累计最大值,需自行跟踪。
- 调用
GetProcessMemoryInfo(GetCurrentProcess(), &pmc, sizeof(pmc))获取当前快照 - 没有API能回溯历史最大虚拟内存(
VirtualAlloc总量),只能在每次分配后手动比对并更新本地变量 - 第三方工具如
vmmap.exe(Sysinternals)可离线分析,但无法嵌入C++运行时采集
跨平台统一采集逻辑几乎不存在。Linux靠/proc,Windows靠轮询+自维护,macOS则依赖task_info()和host_statistics(),三者语义不一致——别指望一个函数名能通用。


















