getrlimit查RLIMIT_AS是获取Linux进程虚拟内存提交上限的最直接方式,其值表示brk/mmap可成功申请的虚拟地址空间总量(字节),软限制rlim_cur和硬限制rlim_max分别反映当前生效值与上限。

Linux下用getrlimit查RLIMIT_AS是最直接方式
Linux进程的虚拟内存提交上限由RLIMIT_AS(address space limit)控制,不是总内存或物理内存,而是进程能调用brk/mmap成功申请的虚拟地址空间总量。它默认常为RLIMIT_INFINITY,但可能被ulimit -v、容器限制(如cgroup v1的memory.limit_in_bytes不直接影响它,但cgroup v2的memory.max配合内核配置可间接触发OOM)或父进程设限。
实操建议:
- 包含头文件:
#include <sys/resource.h> - 调用
struct rlimit rl; getrlimit(RLIMIT_AS, &rl);,rl.rlim_cur即当前软限制(单位字节),rl.rlim_max为硬限制 - 若返回-1且
errno == EINVAL,说明该系统不支持此资源类型(极少见) - 注意:该值不反映实际可用虚拟内存(比如高位地址已被内核保留),仅表示内核允许的最大提交量
Windows需用GetProcessMemoryInfo配合GetPerformanceInfo
Windows没有等价于RLIMIT_AS的单一限制项。用户态程序无法直接读取系统级虚拟地址空间配额(如/proc/sys/vm/max_map_count在Linux是另一回事),但可通过两个API拼凑出近似判断:
-
GetProcessMemoryInfo获取PROCESS_MEMORY_COUNTERS_EX.PrivateUsage——当前已提交的私有字节数 -
GetPerformanceInfo拿到PERFORMANCE_INFORMATION.CommitLimit——全系统虚拟内存提交上限(含页面文件),减去CommitTotal可得剩余空间 - 二者相加并非进程上限:Windows按会话/作业对象施加限制,普通进程通常无显式配额,真正瓶颈常是32位进程的4GB地址空间本身(或2GB用户态)
- 64位进程一般不用管这个值,除非启用了
JobObjectBasicAccountingInformation并设置了LimitFlags |= JOB_OBJECT_LIMIT_PROCESS_MEMORY
跨平台时别混淆“虚拟内存大小”和“提交限制”
常见错误是把VirtualAlloc失败、mmap返回MAP_FAILED归因于物理内存不足,其实更可能是虚拟地址空间耗尽或RLIMIT_AS触顶。尤其在频繁mmap(MAP_ANONYMOUS)又不munmap的场景下,即使只申请1MB,几千次后也可能撞上限。
立即学习“C++免费学习笔记(深入)”;
-
ps -o pid,vsize,rss,vsz <pid></pid>中vsize(Linux)或VM(Windows任务管理器)显示的是已分配的虚拟地址空间,不等于已提交 - 真正关键的是“提交”动作:Linux中
mmap带MAP_POPULATE才立即提交;Windows中VirtualAlloc默认只保留地址,VirtualAlloc+MEM_COMMIT才真正提交 - 调试技巧:Linux下
cat /proc/<pid>/status | grep Vm</pid>看VmPeak和VmSize,对比getrlimit结果;Windows用vmmap.exe(Sysinternals)观察各区域的commit状态
容器环境里RLIMIT_AS可能被覆盖但不生效
Docker或Kubernetes默认不限制RLIMIT_AS(即保持unlimited),哪怕设置了memory: 512Mi。这是因为cgroup memory controller管的是物理页+swap用量,而RLIMIT_AS是内核资源限制框架(setrlimit)独立控制的。两者不自动同步。
- 若需强约束,必须显式用
--ulimit as=536870912(单位字节)启动容器 - 否则,进程可能成功
mmap远超容器内存限制的虚拟空间,但首次访问时触发OOM Killer——此时看dmesg会有Out of memory: Kill process而非Cannot allocate memory - Kubernetes中对应字段是
securityContext.resources.limits.memory,它只影响cgroup,不影响RLIMIT_AS;真要限制得靠PodSecurityPolicy(已弃用)或RuntimeClass配合自定义runc配置
getrlimit给的是明确数值,Windows上得组合多个API,容器里还得确认运行时是否透传了限制。最易忽略的是:32位程序在接近4GB时地址空间碎片化导致mmap失败,此时RLIMIT_AS明明还有余量,却再也分不出连续页——那得换64位或改用内存池。


















