Windows 下应调用 GlobalMemoryStatusEx 并正确初始化 dwLength,获取 ullAvailPhys(空闲物理内存)、ullTotalPageFile 和 ullAvailPageFile(提交限制相关);Linux 应解析 /proc/meminfo 中 MemAvailable、SwapTotal、SwapFree 等字段,避免硬编码偏移;跨平台不可依赖 sysconf(_SC_PHYS_PAGES),须按系统 dispatch 实现。

Windows 下用 GlobalMemoryStatusEx 获取空闲物理内存和提交限制
直接调用 GlobalMemoryStatusEx 是 Windows 平台最可靠的方式,它返回 MEMORYSTATUSEX 结构,其中 ullAvailPhys 是当前可用物理内存(字节),ullTotalPageFile 和 ullAvailPageFile 分别是页面文件总大小和剩余大小,而 ullAvailVirtual 不代表物理空闲,别误用。
常见错误是传入未初始化或尺寸不对的结构体——必须先设 dwLength = sizeof(MEMORYSTATUSEX),否则函数返回 false 且不填充数据。示例关键步骤:
MEMORYSTATUSEX memInfo;
memInfo.dwLength = sizeof(MEMORYSTATUSEX);
if (GlobalMemoryStatusEx(&memInfo)) {
printf("Free physical: %llu MB\n", memInfo.ullAvailPhys / (1024 * 1024));
printf("Total page file: %llu MB\n", memInfo.ullTotalPageFile / (1024 * 1024));
printf("Free page file: %llu MB\n", memInfo.ullAvailPageFile / (1024 * 1024));
}
-
ullAvailPhys包含 standby list 中的内存,系统认为“空闲”,但不是所有都可立即分配 - 若程序以低完整性级别运行(如 IE 沙箱、UAC 受限进程),
ullAvailPhys可能被人为压低,不代表真实硬件状态 - 该 API 不区分 LRU、modified 或 zeroed 页面,只反映内核当前标记为“available”的总量
Linux 下读取 /proc/meminfo 解析空闲内存与交换区详情
Linux 没有统一系统调用暴露这些指标,标准做法是解析 /proc/meminfo 文件。重点字段包括:MemAvailable:(内核估算的真正可分配内存)、MemFree:(仅 page cache/buffer 中完全未使用部分,通常远小于前者)、SwapTotal: 和 SwapFree:。
别硬编码字段偏移或逐行 strstr 匹配——字段顺序不保证,且某些发行版(如容器环境)可能缺 MemAvailable。应逐行扫描,按冒号分隔,跳过空白后 trim 尾部单位(kB)。示例逻辑:
FILE* f = fopen("/proc/meminfo", "r");
char line[256];
while (fgets(line, sizeof(line), f)) {
if (strncmp(line, "MemAvailable:", 13) == 0) {
sscanf(line + 13, "%llu kB", &mem_avail);
} else if (strncmp(line, "SwapTotal:", 10) == 0) {
sscanf(line + 10, "%llu kB", &swap_total);
} else if (strncmp(line, "SwapFree:", 9) == 0) {
sscanf(line + 9, "%llu kB", &swap_free);
}
}
-
MemAvailable是 Linux 3.14+ 引入的估算值,比MemFree + Buffers + Cached - SReclaimable更准,优先用它 - 容器中(如 Docker)
/proc/meminfo显示的是宿主机全局值,不是容器 cgroup 限额;要获取容器实际可用内存,得读/sys/fs/cgroup/memory/memory.limit_in_bytes和memory.usage_in_bytes -
SwapFree可能大于SwapTotal(罕见,多因内核 bug 或休眠镜像残留),需做校验
跨平台封装时为什么不能只依赖 sysconf(_SC_PHYS_PAGES)
sysconf(_SC_PHYS_PAGES) 返回的是总物理页数,不是空闲量;它不随内存压力变化,也无法反映页面文件或 swap 状态。很多初学者误以为这是“可用内存”,结果监控数据长期恒定,完全失真。
同理,getpagesize() 只给页大小,两者相乘只是总内存容量,跟“空闲”毫无关系。POSIX 标准里压根没定义获取空闲内存的接口,所以跨平台库(如 Qt、Boost)也都不提供这类功能。
- macOS 同样无标准 API,需用
host_statistics+HOST_VM_INFO,返回的是vm_statistics_data_t,其中free_count是空闲页数,但需换算且受 zone 压缩影响 - 若强行抽象一层跨平台接口,建议按平台 dispatch:Windows 走
GlobalMemoryStatusEx,Linux 走/proc/meminfo,macOS 走host_statistics,别试图用一个函数签名掩盖底层差异 - 注意
long在不同平台宽度不同(LP64 vs LLP64),所有计数字段务必用uint64_t接收,避免截断
提交内存(Commit Limit)在 Windows 和 Linux 中的本质区别
Windows 的“提交内存”是明确的资源配额概念:进程 commit 的虚拟内存总量不能超过 ullTotalPageFile + ullTotalPhys(即物理内存 + 页面文件上限),超限会触发 STATUS_NO_MEMORY。而 Linux 没有 Commit Limit 这一机制——它默认启用 overcommit(/proc/sys/vm/overcommit_memory = 0 or 1),只有在 =2 时才按 vm.overcommit_ratio 限制,且该限制包含物理内存与 swap,但计算方式与 Windows 不同。
- Windows 的
ullTotalVirtual是用户态地址空间上限(通常 2GB 或 8TB),不是 Commit Limit;Commit Limit 需自己算:memInfo.ullTotalPageFile + memInfo.ullTotalPhys - Linux 中没有等价于
ullAvailPageFile的“当前可提交剩余量”,因为 overcommit 行为使“承诺”本身不可静态预估 - 监控告警若依赖“提交使用率”,Windows 可算
(CommitTotal / CommitLimit),Linux 则只能退回到(Committed_AS / (MemTotal + SwapTotal))(来自/proc/meminfo的Committed_AS字段),但后者是启发式估算,非硬限制
实际部署时,MemAvailable 在低内存压力下可能虚高,而 Windows 的 ullAvailPhys 在长时间运行后易受 standby list 积累影响——这两个值都偏向乐观估计,真要做内存敏感决策(比如大图解码、缓存预加载),得结合最近 10 秒的 psutil 类轮询或内核事件(如 Windows 的 MEMORY_RESOURCE_NOTIFICATION)才够稳妥。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











