Linux 写时复制问题 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
请不要在回答技术问题时复制粘贴 AI 生成的内容
div class="box" id="pro-campaign-container">
ChainLock

Linux 写时复制问题

  •  
  •   ChainLock 2024 年 9 月 1 日 2619 次点击
    这是一个创建于 599 天前的主题,其中的信息可能已经有所发展或是发生改变。
    #include <stdio.h> #include <stdlib.h> #include <sys/types.h> #include <unistd.h> int g=100; int main() { static int x=66; pid_t pid = fork(); if (pid==-1){ printf("创建进程失败\r\n"); } if (pid==0){ printf("pid=%d g=%d,x=%d,g=%p,x=%p\r\n",pid,g,x,&g,&x); g=111; x=222; printf("我子进程 pid=%d,g=%d,x=%d,g=%p,x=%p\r\n",pid,g,x,&g,&x); }else{ printf("pid=%d,g=%d,x=%d,g=%p,x=%p\r\n",pid,g,x,&g,&x); g=666; x=777; printf("我是父进程 pid=%d,g=%d,x=%d,g=%p,x=%p\r\n",pid,g,x,&g,&x); } return 0; } 

    输出

    pid=4502,g=100,x=666,g=0x601044,x=0x601048 我是父进程 pid=4502,g=666,x=777,g=0x601044,x=0x601048 pid=0 g=100,x=666,g=0x601044,x=0x601048 我子进程 pid=0,g=111,x=222,g=0x601044,x=0x601048 

    我的问题是:

    子进程修改变量后,会重新开启一块新内存,再我重新修改变量值后,为什么在打印变量的地址还是相同的?

    21 条回复    2024-09-02 13:16:25 +08:00
    sagaxu
        1
    sagaxu  
       2024 年 9 月 1 日
    你打印的是虚拟内存的地址,不是物理内存,两个进程可以有完全一样的虚拟内存布局
    ChainLock
        2
    ChainLock  
    OP
       2024 年 9 月 1 日
    @sagaxu #1 父子虚拟内存地址一样,父子进程中各自修改数据,都不互相影响
    shijingshijing
        3
    shijingshijing  
       2024 年 9 月 1 日
    @ChainLock 打印出来的内存是虚拟内存地址,实际物理内存地址是 MMU 负责转换的。
    ChainLock
        4
    ChainLock  
    OP
       2024 年 9 月 1 日
    我纠结的点在于,父子进程第一次打印变量地址 相同,我可以理解,我在子进程里面都改变这个变量的值,再次打印还是相同的
    R4rvZ6agNVWr56V0
        5
    R4rvZ6agNVWr56V0  
       2024 年 9 月 1 日   2
    wkla
        6
    wkla  
       2024 年 9 月 1 日
    @ChainLock #4 进程内存空间互相独立,这点你得先整明白。然后物理内存(绝对地址)和虚拟内存映射的分页机制你得先整明白。

    写时复制可以在更底层做,没必要反应到进程虚拟内存上。你想象的就是写的时候,变量会开一个新地址放。事实上可能是这整个内存页在物理地址上不一样,也没必要变动进程的虚拟地址。
    dhb233
        7
    dhb233  
       2024 年 9 月 1 日
    对于内核来说,能让程序正常运行,还能让指针地址改变是更难的事情吧。。。
    写时拷贝是硬件提供的能力,fork 之后,设置页不可写,写的时候触发中断,复制一份就可以了
    heiher
        8
    heiher  
       2024 年 9 月 1 日 via Android
    COW 是为被写的虚拟地址创建了一个新的物理页,复制数据到上面,再映射到触发写进程的该虚拟页上。从始至终虚拟地址不变,物理地址改变。只打印虚拟地址当然看不出来啦。
    wxf666
        9
    wxf666  
       2024 年 9 月 2 日
    @dhb233 #7 请教一下,4GB 的程序被 fork 之后,系统会设置 100W 页不可写吗?(假设 4KB/页)
    ho121
        10
    ho121  
       2024 年 9 月 2 日 via Android
    写时复制是在比进程这个层级更底层中做的,对进程这一层是透明的。
    你想想系统怎么可能随时改变进程内的状态(比如某变量的地址),那不就乱套了。
    况且程序中拿到的地址是虚地址,不是物理内存的地址。写时复制是在物理内存级别做的。

    同样的可以参考一下文件系统的写时复制,写时复制是在文件系统层面做的,对文件本身是透明不可见的。不管何时写时复制,对于文件来说,文件还是那个文件,内容不会因为写时复制而改变,只是磁盘上的分布变了。
    yanqiyu
        11
    yanqiyu  
       2024 年 9 月 2 日 via Android
    @wxf666 是,除非是 mmap 的 shared 这种情况,之外父子进程都会看到 ro 的页面,等写入的时候中断介入复制
    r46mht
        12
    r46mht  
       2024 年 9 月 2 日
    @wxf666 概念上是这样的,实际的操作不需要 100w 页一个一个设置。x86 的页表是一个类似于字典树的结构,在父节点上标不可写相当于一次性设置了很多连续的页不可写
    ChainLock
        13
    ChainLock  
    OP
       2024 年 9 月 2 日
    @wkla #6 感谢佬
    ChainLock
        14
    ChainLock  
    OP
       2024 年 9 月 2 日
    @GeekGao #5 感谢佬
    ChainLock
        15
    ChainLock  
    OP
       2024 年 9 月 2 日
    @heiher #8 感谢佬,大彻大悟
    ChainLock
        16
    ChainLock  
    OP
       2024 年 9 月 2 日
    @ho121 #10 我一直把虚地址,物理内存地址搞混了,要想完全搞懂,得去看 Linux 源码了
    ChainLock
        17
    ChainLock  
    OP
       2024 年 9 月 2 日
    @r46mht #12 要想完全搞明白这些,只能去啃 linux 源码 ,我太菜了
    dhb233
        18
    dhb233  
       2024 年 9 月 2 日
    @wxf666 #9 具体的实现不是很清楚。。。至少 fork 的时候,新的进程的页表就是要全创建出来啊,有 100w 个页就要创建 100w 个页表
    ho121
        19
    ho121  
       2024 年 9 月 2 日
    @ChainLock 看源码不至于,看操作系统原理就行
    vituralfuture
        20
    vituralfuture  
       2024 年 9 月 2 日 via Android
    给楼主提供几个意见,这些是操作系统的知识,中国大学 mooc 上找个课程,买几本书,现代操作系统,操作系统导论等经典书籍看一看,然后找国外大学是公开课程跟着做个实验,就能理解了。linux 内核源码很难读,如果不是内核开发,就没有读的必要,里面很多奇技淫巧各种历史遗留。操作系统的理论很早就有了,到现在已经非常完善了,所谓各种内核只不过是将这些理论落地而已,实现不重要,背后的思想设计才是精华
    ChainLock
        21
    ChainLock/strong>  
    OP
       2024 年 9 月 2 日
    @vituralfuture #20 好的,佬
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     5362 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 66ms UTC 07:11 PVG 15:11 LAX 00:11 JFK 03:11
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86