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

fork时未触发写时复制?为何父子进程内存地址仍相同

问题:子进程修改内存后,父子进程内存地址为何一致?

根据写时复制(copy-on-write)机制,fork创建子进程后,初始时父子进程指向同一内存区域,直到其中一个进程修改内存时,才会复制该内存并在副本上执行修改操作。但如下代码的输出显示,子进程修改gFlag后,父子进程的gFlag内存地址仍保持一致,请问这一现象的原因是什么?

using namespace std;
using ULL = unsigned long long;
int gFlag = 0;

int main ()
{
        gFlag = 1;
        cout << (ULL)&gFlag << endl;

        pid_t ret = fork ();

        if (ret > 0) {

                sleep (6);

                cout << "Parent: " << gFlag << endl;
                cout << "Parent: " << (ULL)&gFlag << endl;

                return 0;
        } else {

                gFlag = 15;
                cout << "Child: " << gFlag << endl;
                cout << "Child: " << (ULL)&gFlag << endl;
        }

        return 0;
}

输出结果:

94022699245908
Child: 15
Child: 94022699245908
Parent: 1
Parent: 94022699245908

解答

这是因为你打印的是虚拟地址,而非真实的物理内存地址:

  • 现代操作系统都采用虚拟内存机制,每个进程都拥有独立的虚拟地址空间。fork创建子进程时,会完整复制父进程的虚拟地址映射关系,所以父子进程的虚拟地址空间布局完全一致。
  • 写时复制(COW)机制作用的是物理内存页:当子进程修改gFlag时,操作系统会为该变量所在的物理内存页创建一个副本,子进程的虚拟地址会重新映射到这个新的物理页;而父进程的虚拟地址依然映射到原来的物理页。
  • 但父子进程的虚拟地址是各自进程内部的逻辑地址,二者的虚拟地址空间相互独立,所以&gFlag打印出的数值完全相同——这个地址只是进程自己“认知”的地址,和真实的物理内存位置没有直接对应关系。

简单总结:虚拟地址只是进程内部的逻辑标识,父子进程的虚拟地址可以完全相同,但它们背后映射的物理内存已经在修改操作后分开了,所以变量值不同,但打印的地址看起来一致。


内容的提问来源于Stack Exchange,提问作者Vipul Gupta

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.11 12:52:28