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

mmap()分配大内存失败求助:虚拟内存充足仍报errno12

问题分析与解决方案

你遇到的问题核心在于错误地将RLIM_INFINITY(无限制的虚拟内存上限)当作实际可分配的虚拟地址空间大小来计算,导致你尝试分配的内存大小远超系统硬件支持的实际虚拟地址空间,最终触发ENOMEM(错误码12)。

为什么会出现这个问题?

看你的输出:memory size is 18446744073709551615 bytes,这个值是RLIM_INFINITY——它表示系统允许进程使用的虚拟内存没有硬限制,但这不代表你的进程真的能分配这么大的内存:

  • 64位架构(比如x86_64)的用户态虚拟地址空间是有硬件上限的,通常只有128TB(对应247位地址),而你计算的`array_size`是2.3EB(261字节),这远远超出了实际可用的虚拟地址范围,mmap根本找不到这么大的连续虚拟地址区间来分配。
  • 即使忽略地址空间限制,这么大的内存也需要对应的交换空间来支撑写入操作,几乎没有系统会配置这么大的交换分区。

你尝试的方法为什么无效?

  • MAP_NORESERVE:这个标志只是告诉内核不要预分配交换空间,但解决不了虚拟地址空间不足的问题——内核还是需要找到足够大的连续虚拟地址范围,而你的请求大小已经远超硬件支持的上限。
  • 减小到1/32:即使是1/32,RLIM_INFINITY/32也有5.7e17字节,还是远大于128TB,所以依然会失败。

解决方案

  1. 先判断虚拟内存上限是否为无限大:如果mem_limit.rlim_cur等于RLIM_INFINITY,就用对应架构的实际虚拟地址空间上限来计算,而不是直接用这个无限大的值。
  2. 基于系统架构设置合理的上限:比如x86_64用户态虚拟地址空间最大为128TB(1ULL << 47),你可以用这个值来计算分配大小。
  3. 动态检测可用虚拟地址空间:或者通过尝试逐步分配的方式,找到最大的可分配连续内存。

修改后的代码示例

#include <stdio.h>
#include <stdlib.h>
#include <sys/resource.h>
#include <sys/mman.h>
#include <errno.h>
#include <stdint.h>

int main() {
    struct rlimit mem_limit;
    if (getrlimit(RLIMIT_AS, &mem_limit) != 0) {
        return -errno;
    }

    // 处理RLIM_INFINITY的情况,用x86_64的用户态虚拟地址空间上限(128TB)
    uint64_t max_virtual_mem;
    if (mem_limit.rlim_cur == RLIM_INFINITY) {
        // x86_64用户态虚拟地址空间通常是128TB(2^47字节)
        max_virtual_mem = 1ULL << 47;
    } else {
        max_virtual_mem = mem_limit.rlim_cur;
    }

    // 设置虚拟内存上限为最大允许值
    mem_limit.rlim_cur = mem_limit.rlim_max;
    if (setrlimit(RLIMIT_AS, &mem_limit) != 0) {
        return -errno;
    }

    uint64_t array_size = max_virtual_mem / 8;
    printf("max virtual memory is %lu bytes, array size is %lu bytes\n", max_virtual_mem, array_size);

    char* mem_array = (char*)mmap(0, array_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
    if (mem_array == MAP_FAILED) {
        printf("mmap failed with %d. allocation size = %lu\n", errno, array_size);
        return -errno;
    }

    printf("mmap succeeded, address: %p\n", mem_array);
    // 尝试写入一个字节测试
    mem_array[0] = 'a';
    printf("written first byte successfully\n");

    munmap(mem_array, array_size);
    return 0;
}

额外注意事项

  • 不同架构的虚拟地址空间上限不同:比如ARM64的用户态虚拟地址空间可能是48位(256TB),你可以根据目标架构调整max_virtual_mem的值。
  • 即使mmap成功,写入大量数据时依然需要足够的物理内存或交换空间,否则会触发OOM killer。
  • 如果不需要连续内存,可以多次调用mmap分配小块内存,而不是追求一个超大的连续块。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.11 07:27:03