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

子进程中调用free()是否会触发写时复制(copy-on-write)?

关于fork()写时复制与子进程free()的疑问

来自man fork(2)文档:
在Linux系统中,fork()通过写时复制(copy-on-write)页实现,因此它仅需花费复制父进程页表、为子进程创建唯一任务结构的时间与内存开销。

基于此,来看如下示例代码:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>

int main(void)
{
    char *data = malloc(100);

    snprintf(data, 100, "%s", "Hello world!");

    pid_t pid = fork();

    if (pid == -1)
    {
        perror("fork");
        exit(EXIT_FAILURE);
    }
    if (pid == 0)
    {
        // start of child process
        printf("I'm the child\n");
        // Do the child stuff ...
        puts(data);
    }
    else
    {
        // start of parent process
        printf("I'm the parent\n");
        // Do the parent stuff ...
        puts(data);
        // Wait for child process
        if (wait(NULL) == -1)
        {
            perror("wait");
            exit(EXIT_FAILURE);
        }
        free(data);
    }
    return 0;
}

根据我的理解,若资源被复制但未修改,则无需创建新资源,通过malloc分配的内存不会在子进程中复制,子进程仅持有指向父进程内存的指针。

另一方面,若不在子进程中释放资源会导致内存泄漏:

==13024== HEAP SUMMARY:
==13024==     in use at exit: 100 bytes in 1 blocks
==13024==   total heap usage: 2 allocs, 1 frees, 1,124 bytes allocated
==13024== 
==13024== LEAK SUMMARY:
==13024==    definitely lost: 100 bytes in 1 blocks
==13024==    indirectly lost: 0 bytes in 0 blocks
==13024==      possibly lost: 0 bytes in 0 blocks
==13024==    still reachable: 0 bytes in 0 blocks
==13024==         suppressed: 0 bytes in 0 blocks
==13024== Rerun with --leak-check=full to see details of leaked memory
==13024== 
==13024== For lists of detected and suppressed errors, rerun with: -s
==13024== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
==13023== 
==13023== HEAP SUMMARY:
==13023==     in use at exit: 0 bytes in 0 blocks
==13023==   total heap usage: 2 allocs, 2 frees, 1,124 bytes allocated
==13023== 
==13023== All heap blocks were freed -- no leaks are possible
==13023== 
==13023== For lists of detected and suppressed errors, rerun with: -s
==13023== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)

这表明应该在子进程中调用free():

if (pid == 0)
    {
        // start of child process
        printf("I'm the child\n");
        // Do the child stuff ...
        puts(data);
        free(data);
    }

问题

子进程中调用free()是否会触发写时复制(copy-on-write)?


回答

会触发写时复制,但并非针对data指向的堆数据页,而是针对malloc维护的堆元数据页(比如空闲链表、内存块大小记录等)。

当子进程调用free(data)时,需要修改malloc内部的堆管理结构——这些结构存储在特定内存页中,fork后这类页是父子进程共享的只读状态。一旦子进程尝试修改这些元数据,内核就会触发COW,为子进程复制出独立的堆元数据页,后续子进程的堆操作将基于这份副本进行,不会影响父进程的堆管理。

至于data指向的实际数据页,free()本身不会修改数据内容,只是标记该内存块为空闲,因此这份数据页不会被复制。只有当父进程后续访问或修改该数据页时,才会触发COW(如果此前未触发过的话)。

另外需要明确:父子进程的堆是完全独立的,子进程调用free()仅会释放自身地址空间中的内存块标记,父进程的free()操作不受影响,两者互不干扰。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.19 17:36:24