操作系统——程序地址空间


前言:学过内存管理的同志,应该都看过下图。我们一般认为下图就是真正的物理内存。但是这并不是真正的内存,听到这有的人懵了,内存就是这样的呀,学的就是如此。说一句网络都是虚拟的,水太深,把握不住。一样,以下是虚拟内存。程序是如何和物理内存打交道的,本篇娓娓道来。
在这里插入图片描述


1. 一段令人困惑的程序

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
int g_val = 0;
int main()
{
 pid_t id = fork();
 if(id < 0){
 perror("fork");
 return 0;
 }
 else if(id == 0)
 {
  g_val=1000;
  printf("child:change-> g_val:%d,%p\n",g_val,&g_val);
 }
 else 
 {
   printf("father:my->g_val:%d,%p\n",g_val,&g_val);
   sleep(3);
 }
 sleep(1);
 return 0;
}

我们知道,子进程会继承父进程的代码和数据。但是我在子进程中修改数据会发生写时拷贝。写时拷贝后面具体讲。上面的代码非常明显:我在子进程中将g_val修改为1000,父进程的g_val不受影响,每个进程都有独立性,这个大家都懂。那么g_val的地址应该会不同,因为同一个地址只能有一个值,我们来看看子进程和父进程的g_val地址是否相同。
在这里插入图片描述
惊奇的发现,g_val的地址尽然相同。这是打破以往常识的。

  • 每个地址只能有一个值
  • 以上的地址绝对不是物理地址,而是虚拟地址
  • os负责将虚拟地址和物理地址产生联系

2. 虚拟地址空间

每个进程都有自己的代码和空间,进程可能需要对物理地址进行操作。但是如何管理进程代码在内存中的存储呢?让每个进程都可以直接和物理内存打交道,是威胁的行为,而且管理起来很复杂。
比如:我在内存中有两个进程,如果直接让进程操作物理地址,那么它有没有可能会占用另一个进程的物理地址,是有可能的,会造成很大的危害。所以引入虚拟地址。


为了方便管理所有的进程,每个进程都由struct mm_struct这一虚拟地址空间来管理。每个进程都认为自己拥有os的所有内存。

在这里插入图片描述
进程是由PCB来管理的,PCB中就有一个指针指向了mm_struct。mm_struct就存储了进程的代码和数据。

2.1 虚拟地址空间mm_struct如何实现空间分段

可以看到上图中,mm_struct被分成多段,如何实现的呢?其实比较简单。
我们来假设实现,不是源代码哦。

struct mm_struct
{
 unsignde int code_start;
 unsignde int code_end;
 unsignde int date_start;
 unsignde int date_end;
}

在32位下,内存是4GB,每个进程都按照4GB来规划虚拟地址空间。就是如上那样 [_start ,_end]为一个
段。那么就是从0X00000000……000~0Xfffffffff……fffff这样的来规划虚拟地址空间的。

2.2 虚拟地址和物理地址如何产生关联

虚拟地址是按照操作系统所有的内存,来规划的。那么该如何真正的使用物理地址呢?那就是构建映射关系:页表。
利用页表我们可以使虚拟地址和物理地址产生映射关系。
在这里插入图片描述

2.3 子进程如何继承父进程的代码和数据

子进程会继承父进程的代码和数据,子进程的PCB是以父进程的PCB为模板来创建的,当然不是完全拷贝父进程的PCB,如PID,PRI等就不一样。那代码和数据是如何共享的呢?
在这里插入图片描述
嗯,就是这样的继承的。

2.4 写时拷贝

页表中有一个权限,不知道大家注意到没有,每次操作都会对于页表中的权限,如果子进程一直都是读代码,那很简单,啥呀不用管;要是子进程要进行写入操作呢?就比如一上来的代码要进行修改变量的值,该怎么办呢?->写时拷贝。

假如子进程要修改变量,g_val。
(1)一开始是这样的,
在这里插入图片描述
(2)但是子进程,要修改g_val的值了。页表上的权限也表示你可以修改,但是在此之前你先稍等,这就是断页中断,你的先拷贝一下,物理地址中的g_val需要拷贝一份来供你修改,这就是写时拷贝。
在这里插入图片描述
(3)可以看到,发生写时拷贝后,g_val在物理地址上多了一份,这就保证了父子进程的独立性。在页表中断时,父子进程什么影响都没有,子进程只不过是要修改数据,页表中断,发生写时拷贝,这都是操作系统干的事。

总结:子进程会默认和父进程代码数据指向同一个物理地址,如果只读那么就相安无事,若要修改数据,那么会发生页表中断来完成写时拷贝,供给子进程来修改。所以默认情况下,只读的代码和数据,操作系统只维护一份;如果要求写入操作,那么会根据具体情况,发生写时拷贝。

3. 解释那令人困惑的程序

有了以上内容的了解,基本上我们都懂了,g_val的虚拟地址是一样的,但是物理地址是分开的。物理地址不同,所以其实本质上是两个变量了。
昂,虚拟的确实不可信哟,但是虚拟的确实很香,香在哪里呢?

4.虚拟地址空间的好处

  • 保护了每个进程的物理内存空间,使得进程的代码和数据风险大大降低
  • 提升了操作系统管理的效率,每个虚拟地址空间都是按照4GB的方式规划内存
  • 内存申请和内存使用,时间,空间效率都提升
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

动名词

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值