进程地址空间与写时拷贝

进程地址空间

内核数据结构task_struct中存放着指向mm_struct的结构体指针,该结构体用来描述进程的内存管理信息,包括但不限于页目录与虚拟内存区域。先来看这样一个程序

#include<stdio.h>    
#include<unistd.h>    
int main(void)    
{    
   int num =100;    
    int re = fork();    
    if(re > 0)    
    {    
        printf("The number's address:%p\n",&num);    
        printf("The number:%d\n",num);    
        num = 10;    
        sleep(10);    
        printf("The number's address:%p\n",&num);    
        printf("The number:%d\n",num);    
    }    
    if(re == 0)    
    {    
    
        printf("The number's address:%p\n",&num);    
        printf("The number:%d\n",num);    
        sleep(10);    
        printf("The number's address:%p\n",&num);    
        printf("The number:%d\n",num);                                                 
    
    }    
    return 0;    
}    

这是运行结果: 

可以见到,第一次输出,父子进程的值与地址都相同;但在第二次输出,父进程的变量被修改,父子进程的值不一样,但是地址却一样。

        所以,这里的地址(也就是语言级别的地址——指针)并不是物理地址,而是虚拟地址——线性地址、逻辑地址(但二者又略有出入)。

        进程地址空间通过树状结构的多级页表与物理地址建立联系,即task_struct -> mm_struct -> 页目录 -> 页表,再通过页表找到对应的物理地址,在物理地址取出数据——由外存加载至内存。

       基于各进程都有自己的内核数据结构, 这种机制保持了进程的独立性的同时也保护了物理地址——当进程非法访问时,会被页表检测并拦截。

写时拷贝(Copy on Write)

        在上述情况中,为了保持进程的独立性,当父子进程任何一方尝试写入数据至同一地址时(在未做出写入操作时,父子进程共享同一物理地址,但也仅是可读),操作系统会先对数据进行拷贝,而后放入新开的物理地址,再改变页表的映射,其后进程才可以进行修改。这种思想就是写时拷贝。

        这种技术被广泛地引用在操作系统中,当一个程序运行结束时,操作系统并不会立即将其数据清除,因为这个程序可能还会在运行一次。写文件操作也是,只有我们关闭文件,操作系统才会将其写入外存;但这也意味着,当主机非正常关闭时,文件就会丢失,但为了性能这样做是非常值得的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值