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

启用Copy-on-Write仍fork失败?RockyLinux内存分配问题求助

问题:写时复制机制下fork子进程仍失败的原因及解决

我在一台4TB内存的RockyLinux 8.10服务器上运行如下程序:父进程先通过malloc分配45GB内存,再fork出100个子进程。由于fork采用写时复制(Copy-on-Write)机制,我认为所有子进程可以共享这45GB内存,无需实际复制物理内存,但程序却报错:

Failed to fork 0 (total of 0GB allocated): Cannot allocate memory

程序未对mem数组执行任何写入操作,按预期应该能成功运行,请问问题出在哪?是否需要配置系统参数来启用写时复制?

附上代码:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <signal.h>

#define GB 45
#define FORKS 100
void main() {
    unsigned char *mem[GB];
    int i;
    for (i = 0; i < GB; i++) {
        mem[i] = malloc(1024*1024*1024);
        if (mem[i] == NULL) {
            printf("Failed to alloc %d: %s\n", i, strerror(errno));
            return;
        }
    }
    int pids[FORKS];
    for (i =0; i < FORKS; i++) {
        int pid = fork();
        if (pid == 0) {
            sleep(20);
            exit(0);
        }
        if (pid == -1) {
            printf("Failed to fork %d (total of %dGB allocated): %s\n", i, i*GB, strerror(errno));
            for (int j = 0; j < pid; j++) {
                kill(pids[j], SIGTERM);
            }
            return;
        }
        pids[i] = pid;
    }
    for (int j = 0; j < FORKS; j++) {
        kill(pids[j], SIGTERM);
    }
    printf("Success\n");
}

核心原因:虚拟内存额度检查与OOM机制

写时复制是Linux内核默认启用的机制,不需要额外配置,问题出在fork时的虚拟内存预留检查:

  • 内核fork子进程时,会假设子进程可能会写入所有共享的内存页,因此会检查系统是否能为子进程预留足够的虚拟内存地址空间(即使实际不会分配物理内存)。
  • 你的场景中,父进程已占用45GB虚拟内存,每个子进程创建时,内核会认为它需要额外45GB虚拟内存额度,100个子进程+父进程总共需要45GB * 101 = 4545GB的虚拟内存空间。如果系统的物理内存+swap总和不足这个值,或者进程的虚拟内存限制(RLIMIT_AS)低于这个值,就会触发Cannot allocate memory错误。

解决方法

1. 调整进程虚拟内存限制

用ulimit -v查看当前进程的虚拟内存限制(RLIMIT_AS),默认可能是无限制,但如果系统虚拟内存(物理+swap)不足,仍会失败。

临时调整限制:

ulimit -v unlimited

或者在代码中通过系统调用永久修改(需在内存分配前执行):

#include <sys/resource.h>

// 在malloc循环前添加
struct rlimit rl;
getrlimit(RLIMIT_AS, &rl);
rl.rlim_cur = RLIM_INFINITY; // 设置为无限制
setrlimit(RLIMIT_AS, &rl);

2. 优化内存分配方式

代码中多次malloc 1GB会产生内存碎片,改为一次性分配45GB内存,能让内核更高效管理虚拟内存:

unsigned char *mem = malloc(45LL * 1024 * 1024 * 1024);
if (!mem) {
    printf("Failed to alloc: %s\n", strerror(errno));
    return;
}

3. 检查并扩展swap空间

如果物理内存4TB但swap过小,内核计算虚拟内存可用量时会受限。用swapon -s查看swap大小,必要时新增swap分区或文件。

4. 修复代码中的bug

  • 错误提示里的total of %dGB allocated逻辑错误,应该是固定的45GB,而非i*GB;
  • fork失败后的kill循环条件错误,j < pid应改为j < i(因为pid=-1,此时已成功创建了i个子进程):
printf("Failed to fork %d (total of %dGB allocated): %s\n", i, GB, strerror(errno));
for (int j = 0; j < i; j++) {
    kill(pids[j], SIGTERM);
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.14 18:13:26