You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在macOS与Windows系统中检测内存碎片化以排查OOM问题

你遇到的这种OOM找不到泄漏、怀疑内存碎片化的情况太常见了——长期运行的进程很容易把内存拆成一堆小空闲块,总内存够但就是拿不出连续的大块。我分平台给你梳理下具体的检测方法:

macOS 平台的内存碎片化检测

1. 直接用vmmap获取碎片化数据

你提到的vmmap碎片化计算公式完全正确:

(DIRTY+SWAP FRAG SIZE) = DIRTY SIZE - BYTES ALLOCATED
FRAG = (DIRTY+SWAP FRAG SIZE) / DIRTY SIZE × 100.0

其实vmmap本身的输出就包含你要的DIRTY SIZE和BYTES ALLOCATED,不用额外找工具:

  • 运行vmmap <你的进程PID>,定位到进程的malloc相关内存段(比如MALLOC_LARGE、MALLOC_SMALL、MALLOC_TINY);
  • 每个段下的Dirty行对应DIRTY SIZE(例:Dirty: 123456 KB);
  • 同一段的Allocated行就是BYTES ALLOCATED(例:Allocated: 98765 KB);
  • 嫌手动计算麻烦?直接看输出里的FRAG列,它已经帮你算好碎片化百分比了。

另外,vmmap -summary <PID>能快速输出进程整体内存的碎片化概况,不用翻冗长的详细日志。

2. 解决mstats与vmmap数据不匹配的问题

mstats只跟踪libmalloc分配器管理的内存,而vmmap是系统级的全局内存视图,包含了内核分配内存、共享库内存等其他区域,数据不一致是正常的。如果想从代码层面获取和vmmap中malloc段对齐的统计数据,可以用malloc_zone_statistics API,它能直接查询每个malloc zone的已分配、空闲内存细节,和vmmap的malloc段数据完全匹配。

3. 辅助工具:heap命令

运行heap -s <PID>可以查看进程堆的分配统计,比如不同大小内存块的数量——如果小内存块占比极高,且空闲块数量多但单个块极小,这就是典型的碎片化特征。

Windows 平台的内存碎片化检测

Windows的内存模型和macOS差异很大,你用VirtualQuery和GetProcessMemoryInfo的思路是对的,但需要针对性调整分析逻辑:

1. 改造VirtualQuery分析内存区域分布

你当前的vminfo函数只统计了总free、reserved、committed内存,这不足以检测碎片化。要判断碎片化,你需要重点分析空闲内存块的分布:

  • 遍历所有MEM_FREE类型的内存区域,记录每个空闲块的大小;
  • 计算总空闲内存和最大连续空闲块大小:如果总空闲内存足够,但最大连续块远小于你需要分配的内存尺寸,那就是碎片化导致的OOM;
  • 额外统计空闲块数量——数量越多、平均块越小,碎片化越严重。

给你修改后的代码示例:

static void vminfo_fragmentation(unsigned long *total_free, unsigned long *max_free_block, unsigned int *free_block_count) {
    MEMORY_BASIC_INFORMATION memory_info;
    memory_info.BaseAddress = 0;
    *total_free = 0;
    *max_free_block = 0;
    *free_block_count = 0;
    while (VirtualQuery(memory_info.BaseAddress, &memory_info, sizeof(memory_info))) {
        if (memory_info.State == MEM_FREE) {
            *total_free += memory_info.RegionSize;
            *free_block_count += 1;
            if (memory_info.RegionSize > *max_free_block) {
                *max_free_block = memory_info.RegionSize;
            }
        }
        memory_info.BaseAddress = (char *)memory_info.BaseAddress + memory_info.RegionSize;
    }
}

2. 用HeapWalk分析堆级碎片化

如果你的OOM来自堆分配(比如malloc/new),用HeapWalk分析进程的堆会更精准:

  • 先用GetProcessHeaps获取进程的所有堆句柄;
  • 用HeapWalk遍历每个堆的内存块,区分已分配块和空闲块;
  • 统计空闲块的大小分布、最大空闲块,以及碎片化率(公式参考:(总空闲堆内存 - 最大空闲堆块) / 总空闲堆内存 * 100%)。

这种方法能直接定位到堆内部的碎片化情况,比系统级的VirtualQuery更贴近你的业务分配逻辑。

3. GetProcessMemoryInfo的辅助作用

PROCESS_MEMORY_COUNTERS_EX里的指标更多是整体内存使用概况,比如:

  • PrivateUsage:进程私有提交的内存总量;
  • WorkingSetSize:当前驻留在物理内存中的内存量;

这些指标不能直接检测碎片化,但可以结合VirtualQuery的结果佐证——比如PrivateUsage很高,但总空闲内存也不低,就更能确认是碎片化导致的分配失败。

总结

  • macOS:优先用vmmap <PID>查看FRAG列,或手动提取DIRTY SIZE和BYTES ALLOCATED计算;代码层面用malloc_zone_statistics获取精准的malloc分配数据;
  • Windows:用VirtualQuery分析系统级空闲内存块分布,或用HeapWalk分析堆内部的碎片化;结合GetProcessMemoryInfo的整体指标辅助验证。

内容的提问来源于stack exchange,提问作者Murat Şeker

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.28 11:43:16