【OS】进程地址空间与虚拟存储空间

前言:

在之前学编程的时候,我们就知道了数据的几个存储位置,大概是这样的一个图:

 然后我们运行程序:

 我们可以看到内存分布确实是按照左边的表来分配的

-----------
感知地址空间 

 现在,我们写了这样一段代码:

很简单的代码,创建一个子进程,然后打印pid\ppid,同时再打印父进程的pid\ppid

看看效果:

 

这些都没问题,但是刚刚代码里面我又多定义了一个变量,假设现在我要看看这个变量,我就直接打印嘛,如下图:

 

 

运行:

 

 

还是没问题嘛,那你演示这些有什么用吗?

现在val的值是100,没变,父子进程读到的值都是一样的,地址也是一样的,但是如果在进程里面修改了值呢?

再看:

 运行:

 这就是一个问题了,我们学过编程,知道一个地址只会有一个确定的值,但是上面父子进程打印的val怎么不一样呢?

很明显是地址的问题,C/C++里面,我们使用的地址,绝对不是物理地址,就是真实地址,如果是真实地址,这种一个地址两个值是不可能出现的。

那这是什么?

可以理解为,虚拟地址。

-----------

那为什么操作系统不让直接看到物理地址呢?

因为内存其本身是一个硬件,只能被动的写入读取,这里我举个例子:

这里有一块地,你跟邻居说好一人分一半,然后你在地上种玉米什么的植物,你跟邻居划分的很明确,不会出现什么我种你那边去了之类的情况,但是有一天,又来一个人,他也要种地,然后你跟邻居一商量,行,分了一块地给他。

但是这个人不会种,也不知道什么界限,他就在地上随便种,你去看自己的玉米的时候发现玉米已经被拔掉了,邻居肯定不会做这种事,但是那个新来的会不会做呢?

系统也是如此,早期的系统分配空间是直接分配的,但是这就很依靠程序员自身掌控能力,如果程序员写错了一个地方,修改了一块本不该被修改的空间,那就会出现错误。

为了解决这种问题,就有人想了个办法,这样,你要空间,可以,我给你开,但是这块空间的真实地址跟你看到的地址可能会有偏差,可以看下图:

 这么看地址空间可能有点抽象,那我们是这样子呢:

每一个虚拟地址都映射了一个在内存中真实存在的物理地址,而这个,我们叫做页表 。

系统先将程序加载到内存,然后将其变为进程,每一个进程,操作系统都会为其构建一个页表结构。

通过这个页表的映射,就可以通过虚拟地址找到真实的物理地址。

那为什么这里的val会有两个值?

不知道你还记不记得,进程的几大特效里面,有一条叫做:独立性

这个独立性是怎么确保的呢?

页表,通过这个,虚拟地址映射的物理地址不一样,这里可以看下面的图。

原本不修改时,他们指向的同一块空间:

但是如果修改了,那就要出写时拷贝,怎么理解?

就是将修改的那个值重新分配一块空间,然后将原本指向val的指针指向新的空间:

 

所以这里就回答一下fork的两个返回值,pid_t id同一个变量为什么会有两个值。

pid_t本质是父进程定义的变量,fork内部,return会被执行两次,return的本质是将值写到接收返回值的变量中。

所以当id = fork()的时候,谁先返回,谁就要发生写时拷贝,就跟上面一样,这就说明了为什么地址是一样的,但是值不一样。

因为其本质是一个虚拟地址,真实对应的物理地址是不一样的。

------

为什么要有虚拟地址空间,就有一下几个原因:

1、保护了内存,就好像上面说的,当你的程序出现了错误,非法访问之类的,它就可以审核之后将其拦截。

2、进程管理,你的进程运行到哪一部分,我加载哪一部分,就不会出现你占了一大块内存,但是又不用的情况。

3、当程序运行起来,变成进程之后,操作系统是随机分配的一块空间,这样就会出现程序运行的地址是不确定的情况,如果用了页表,进行统一管理,就可以直接找到对应的地址来编译加载所有程序,简化了进程的设计和实现。

--------

感谢观看,希望对你有所帮助

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值