当前位置: 首页 > news >正文

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

文章目录

      • 1. 一段令人困惑的程序
      • 2. 虚拟地址空间
        • 2.1 虚拟地址空间mm_struct如何实现空间分段
        • 2.2 虚拟地址和物理地址如何产生关联
        • 2.3 子进程如何继承父进程的代码和数据
        • 2.4 写时拷贝
      • 3. 解释那令人困惑的程序
      • 4.虚拟地址空间的好处

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


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的方式规划内存
  • 内存申请和内存使用,时间,空间效率都提升

相关文章:

  • JavaScript-操作表单和前端加密
  • 使用disruptor队列实现本地异步消费
  • 在Windows中自动压缩备份文件和目录的脚本
  • 猿创征文|Java计算【生日工具类】看这篇就够了
  • 网络-电脑网络突然变成球形, 网络不可用
  • 848. 有向图的拓扑序列(BFS应用)
  • 物联网开发笔记(8)- 使用Wokwi仿真ESP32开发板实现模数转换和脉宽调制
  • 古怪的Lucene中文分词方案 —— CJKAnalyzer
  • SPDK vhost-user结合SPDK NVMe-oF RDMA性能调优
  • mysql 创建函数
  • 支持十亿级密态数据、低代码,蚂蚁集团发布隐语开放平台
  • 关于kafka常见名词解释,你了解多少?
  • 吴恩达深度学习笔记(四)——深度学习的实践层面
  • KNN-KG论文学习笔记
  • DOM与BOM与Echarts
  • __proto__ 和 prototype的关系
  • 【EOS】Cleos基础
  • 【Linux系统编程】快速查找errno错误码信息
  • 【腾讯Bugly干货分享】从0到1打造直播 App
  • CoolViewPager:即刻刷新,自定义边缘效果颜色,双向自动循环,内置垂直切换效果,想要的都在这里...
  • Cumulo 的 ClojureScript 模块已经成型
  • iOS高仿微信项目、阴影圆角渐变色效果、卡片动画、波浪动画、路由框架等源码...
  • Javascript 原型链
  • js算法-归并排序(merge_sort)
  • js学习笔记
  • Spring Boot快速入门(一):Hello Spring Boot
  • Windows Containers 大冒险: 容器网络
  • 阿里云爬虫风险管理产品商业化,为云端流量保驾护航
  • 不上全站https的网站你们就等着被恶心死吧
  • 从tcpdump抓包看TCP/IP协议
  • 翻译--Thinking in React
  • 基于遗传算法的优化问题求解
  • 用 vue 组件自定义 v-model, 实现一个 Tab 组件。
  • 这几个编码小技巧将令你 PHP 代码更加简洁
  • mysql 慢查询分析工具:pt-query-digest 在mac 上的安装使用 ...
  • 如何用纯 CSS 创作一个菱形 loader 动画
  • #vue3 实现前端下载excel文件模板功能
  • $.proxy和$.extend
  • (13)Hive调优——动态分区导致的小文件问题
  • (42)STM32——LCD显示屏实验笔记
  • (bean配置类的注解开发)学习Spring的第十三天
  • (二开)Flink 修改源码拓展 SQL 语法
  • (附源码)python旅游推荐系统 毕业设计 250623
  • (附源码)ssm基于jsp高校选课系统 毕业设计 291627
  • (附源码)计算机毕业设计SSM疫情居家隔离服务系统
  • (附源码)计算机毕业设计SSM在线影视购票系统
  • (五)网络优化与超参数选择--九五小庞
  • (转)Groupon前传:从10个月的失败作品修改,1个月找到成功
  • (转)LINQ之路
  • (转)大型网站的系统架构
  • .NET 材料检测系统崩溃分析
  • .NET 中让 Task 支持带超时的异步等待
  • .NET/C# 将一个命令行参数字符串转换为命令行参数数组 args
  • .netcore 6.0/7.0项目迁移至.netcore 8.0 注意事项
  • .NET开源项目介绍及资源推荐:数据持久层