windows下用globalmemorystatusex获取可用物理内存需初始化memorystatusex的dwlength字段,调用后取ullavailphys字节数转mb;linux读/proc/meminfo中memavailable字段(单位kb);macos用host_statistics64结合free_count与vm_page_size计算,三者语义不同不可直接等价。

Windows 下用 GlobalMemoryStatusEx 获取可用物理内存
Windows 不暴露“可用物理内存”这个单一数值,而是通过 MEMORYSTATUSEX 结构体提供 ullAvailPhys 字段,它代表当前未被任何进程或系统内核锁定、可立即分配的物理内存字节数(含页面文件缓存中可快速回收的部分)。注意:这不是“空闲内存”,而是操作系统认为“此刻能拿来用”的总量。
实操要点:
-
GlobalMemoryStatusEx必须传入已初始化的MEMORYSTATUSEX,且dwLength = sizeof(MEMORYSTATUSEX),否则返回false - 返回值为
bool,失败时调用GetLastError()查错,常见是结构体长度没设对 -
ullAvailPhys是ULONGLONG类型,直接除以 1024*1024 得到 MB,别用int接收,否则在 4GB+ 内存机器上溢出
MEMORYSTATUSEX memInfo;
memInfo.dwLength = sizeof(MEMORYSTATUSEX);
if (GlobalMemoryStatusEx(&memInfo)) {
std::cout <h3>Linux 下读取 <code>/proc/meminfo</code> 中的 <code>MemAvailable</code>
</h3><p>Linux 从 3.14 内核起引入 <code>MemAvailable</code> 行,它比旧的 <code>MemFree</code> 更准确——考虑了可回收的 slab、pagecache 中未锁页部分等。直接解析该行是最可靠方式,不建议自己算 <code>MemFree + Buffers + Cached - Shmem</code>,因为内核计算逻辑随版本变化。</p><p>实操要点:</p>
- 打开
/proc/meminfo后逐行读取,匹配以"MemAvailable:"开头的行(注意冒号和空格) - 数值单位是 kB,不是字节;需转换为字节时乘以 1024,转 MB 则除以 1024
- 某些嵌入式或精简发行版可能没有
MemAvailable(如老内核或禁用该特性),此时 fallback 到MemFree并加注释说明精度下降
std::ifstream f("/proc/meminfo");
std::string line;
while (std::getline(f, line)) {
if (line.substr(0, 13) == "MemAvailable:") {
size_t pos = line.find_first_of("0123456789");
if (pos != std::string::npos) {
long kb = std::stol(line.substr(pos));
std::cout <h3>macOS 使用 <code>host_statistics64</code> 和 <code>HOST_VM_INFO64</code>
</h3><p>macOS 没有类似 <code>/proc/meminfo</code> 的接口,必须通过 Mach API 调用 <code>host_statistics64</code> 获取 <code>vm_statistics64_data_t</code>,其中 <code>free_count</code> 是空闲页数,乘以 <code>vm_page_size</code> 才是字节数。但注意:这仅是真正空闲页,不含可回收缓存,结果通常显著低于 Linux 的 <code>MemAvailable</code> 或 Windows 的 <code>ullAvailPhys</code>。</p><div class="aritcle_card flexRow artxards">
<div class="artcardd flexRow">
<a class="aritcle_card_img" rel="nofollow" href="/xiazai/skill8828" title="Obsidian (Linux)"><img
src="https://img.php.cn/upload/skill/000/000/081/179228531040284.jpg" alt="Obsidian (Linux)" onerror="this.onerror='';this.src='/static/lhimages/moren/morentu.png'" ></a>
<div class="aritcle_card_info flexColumn">
<a rel="nofollow" href="/xiazai/skill8828" title="Obsidian (Linux)" class="overflowclass">Obsidian (Linux)</a>
<p class="overflowclass">操作 Obsidian 库(纯 Markdown 笔记),并通过 notesmd-cli 实现自动化。</p>
</div>
<a rel="nofollow" href="/xiazai/skill8828" title="Obsidian (Linux)" class="aritcle_card_btn flexRow flexcenter"><b></b><span>下载</span>
</a>
</div>
</div><p>实操要点:</p>
- 需要链接
-framework CoreServices和-framework IOKit,编译时别漏 -
host_statistics64返回的是kern_return_t,成功值为KERN_SUCCESS,不是 0 或 true -
vm_page_size必须用host_page_size查询,不能硬编码 4096 —— macOS 支持大页,实际页大小可能不同
vm_statistics64_data_t vm_stat;
mach_msg_type_number_t count = sizeof(vm_stat) / sizeof(natural_t);
kern_return_t ret = host_statistics64(mach_host_self(), HOST_VM_INFO64,
(host_info64_t)&vm_stat, &count);
if (ret == KERN_SUCCESS) {
vm_size_t page_size;
host_page_size(mach_host_self(), &page_size);
uint64_t avail_bytes = (uint64_t)vm_stat.free_count * page_size;
std::cout <h3>跨平台封装时最易忽略的兼容性细节</h3><p>不同系统对“可用物理内存”的定义差异很大:Windows 包含可快速释放的缓存页,Linux 的 <code>MemAvailable</code> 做了更精细的估算,macOS 只报真正空闲页。这意味着同一台机器,三个平台返回的数值可能相差 2–3 倍。</p><p>如果你在写跨平台监控工具或资源调度逻辑,不要直接比较绝对值,更别拿它做内存不足告警阈值。实际使用中:</p>
- 优先用各平台原生推荐方式(即上面三段列出的),别试图统一成一个公式
- macOS 上若需接近 Linux 的语义,得额外估算 inactive + speculative 页,但稳定性差,一般不建议
- 所有路径读取、API 调用都应加错误 fallback,比如 Linux 读
/proc/meminfo失败时返回 -1,Windows 调用失败时查GetLastError()是否为ERROR_INVALID_PARAMETER
数值本身容易拿到,但“可用”二字背后是各系统内核的策略差异,这点不厘清,后续逻辑很容易误判。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!










