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

MacOS使用MAP_32BIT创建匿名mmap映射返回ENOMEM如何解决?

问题根本原因
  • MacOS的MAP_32BIT标记的行为和Linux存在差异:x86_64架构下该标记仅要求映射地址低于4GB(0xFFFFFFFF),而非Linux默认的前2GB区间;ARM架构的M系列Mac完全不支持该标记,调用时直接返回错误。
  • MacOS 11.x(Big Sur)及以上版本调整了用户态地址空间布局,低4GB空间的绝大部分被系统共享缓存、动态链接器等组件预留占用,空闲区域极少。当mmap传入NULL作为地址提示时,内核无法找到符合MAP_32BIT要求的连续空闲页,因此返回ENOMEM错误,与权限配置、匿名映射本身无关。
可行解决方案

方案1:指定低地址提示+MAP_FIXED_NOREPLACE标记

先通过vmmap <进程ID>命令查询当前进程的低地址空闲区间,将空闲区间的起始地址作为mmap的第一个参数传入,同时添加MAP_FIXED_NOREPLACE标记避免覆盖已有映射:

#include <sys/mman.h>
#include <stdio.h>
#include <stdint.h>

int main() {
    // 示例hint地址为512MB位置,可根据vmmap输出调整为实际空闲地址
    void *hint_addr = (void *)0x20000000;
    void *addr = mmap(
        hint_addr, 
        4096,
        PROT_READ | PROT_WRITE,
        MAP_32BIT | MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED_NOREPLACE,
        -1,
        0
    );
    if (addr == MAP_FAILED)
        perror("mmap");
    else
        printf("%p", addr);
}

该方案仅适用于x86_64架构的Mac设备。

方案2:手动遍历低地址分配(全架构兼容)

不需要依赖MAP_32BIT标记,直接从低地址开始依次尝试分配,直到拿到符合阈值要求的地址:

#include <sys/mman.h>
#include <stdio.h>
#include <stdint.h>

#define ADDR_THRESHOLD 0x7FFFFFFF // 前2GB阈值,如需前4GB可改为0xFFFFFFFF
#define PAGE_SIZE 4096

int main() {
    void *addr = MAP_FAILED;
    // 从64KB开始遍历,避开系统预留的低地址区间
    for (uintptr_t hint = 0x10000; hint < ADDR_THRESHOLD; hint += PAGE_SIZE) {
        addr = mmap(
            (void *)hint,
            PAGE_SIZE,
            PROT_READ | PROT_WRITE,
            MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED_NOREPLACE,
            -1,
            0
        );
        if (addr != MAP_FAILED) {
            if ((uintptr_t)addr <= ADDR_THRESHOLD) {
                break;
            }
            // 分配成功但地址超出阈值,释放后继续尝试
            munmap(addr, PAGE_SIZE);
            addr = MAP_FAILED;
        }
    }
    if (addr == MAP_FAILED)
        perror("低地址内存分配失败");
    else
        printf("分配成功,地址:%p", addr);
}

该方案兼容x86_64和ARM架构的所有MacOS版本,无需依赖MAP_32BIT标记。

注意事项

  • MAP_FIXED_NOREPLACE标记仅在MacOS 10.15及以上版本可用,更低版本可替换为MAP_FIXED,但需要提前确认目标地址未被占用,避免覆盖已有映射导致程序崩溃。
  • 32位程序编译方案仅适用于MacOS 10.14及更低版本,10.15之后系统已停止支持32位程序运行。

内容的提问来源于stack exchange,提问作者Challenger5

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.28 09:39:01