Linux 写时复制问题

ChainLock · 2024-9-1 21:57:59 · 228 次点击
```
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>

int g=100;

int main()
{

        static int x=666;

       
        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
```



### 我的问题是:

#### 子进程修改变量后,会重新开启一块新内存,再我重新修改变量值后,为什么在打印变量的地址还是相同的?
举报· 228 次点击
登录 注册 站外分享
10 条回复  
r46mht 小成 2024-9-2 08:32:52

Linux 写时复制问题

@wxf666 概念上是这样的,实际的操作不需要 100w 页一个一个设置。x86 的页表是一个类似于字典树的结构,在父节点上标不可写相当于一次性设置了很多连续的页不可写
yanqiyu 小成 2024-9-2 07:43:11

Linux 写时复制问题

@wxf666 是,除非是 mmap 的 shared 这种情况,之外父子进程都会看到 ro 的页面,等写入的时候中断介入复制
ho121 小成 2024-9-2 07:20:22

Linux 写时复制问题

写时复制是在比进程这个层级更底层中做的,对进程这一层是透明的。
你想想系统怎么可能随时改变进程内的状态(比如某变量的地址),那不就乱套了。
况且程序中拿到的地址是虚地址,不是物理内存的地址。写时复制是在物理内存级别做的。

同样的可以参考一下文件系统的写时复制,写时复制是在文件系统层面做的,对文件本身是透明不可见的。不管何时写时复制,对于文件来说,文件还是那个文件,内容不会因为写时复制而改变,只是磁盘上的分布变了。
wxf666 小成 2024-9-2 03:54:28

Linux 写时复制问题

@dhb233 #7 请教一下,4GB 的程序被 fork 之后,系统会设置 100W 页不可写吗?(假设 4KB/页)
heiher 小成 2024-9-1 22:48:44
COW 是为被写的虚拟地址创建了一个新的物理页,复制数据到上面,再映射到触发写进程的该虚拟页上。从始至终虚拟地址不变,物理地址改变。只打印虚拟地址当然看不出来啦。
dhb233 小成 2024-9-1 22:41:56
对于内核来说,能让程序正常运行,还能让指针地址改变是更难的事情吧。。。
写时拷贝是硬件提供的能力,fork 之后,设置页不可写,写的时候触发中断,复制一份就可以了
wkla 小成 2024-9-1 22:33:49
@ChainLock #4 进程内存空间互相独立,这点你得先整明白。然后物理内存(绝对地址)和虚拟内存映射的分页机制你得先整明白。

写时复制可以在更底层做,没必要反应到进程虚拟内存上。你想象的就是写的时候,变量会开一个新地址放。事实上可能是这整个内存页在物理地址上不一样,也没必要变动进程的虚拟地址。
GeekGao 小成 2024-9-1 22:31:30
https://i.imgur.com/kybfKzt.png
shijingshijing 小成 2024-9-1 22:06:35
@ChainLock 打印出来的内存是虚拟内存地址,实际物理内存地址是 MMU 负责转换的。
sagaxu 初学 2024-9-1 22:01:14
你打印的是虚拟内存的地址,不是物理内存,两个进程可以有完全一样的虚拟内存布局
返回顶部