【Linux 学习计划】-- 进程地址空间

news2025/6/2 19:21:39

目录

进程地址的引入

进程地址空间基础原理

区域划分的本质

如何理解进程地址空间

越界访问的本质

进一步理解写时拷贝

重谈 fork 返回值

结语


进程地址的引入

我们先来看一段代码:

首先我们可以看到,父进程和子进程是可以同时可以看到一个变量的,这也很正常,因为子进程的数据最开始就是从父进程那里来的

但是我们现在再来看一个代码:

唯一的改动在这里,接下来我们来看一下结果:

这对吗?注意看,这上面两个变量的地址是一样的,但是两个变量的值却是不一样的,这不对啊!!

不知道各位有没有想起我们在学习进程的时候,最开始学到的一个函数,叫做fork,这个函数的返回值也是可以同时返回给同一个参数,但是当时我们就说,这是由于有两个不同的进程,但是我们没有就着那个变量来谈

但是就用最基础的知识来讲,我们就有理由怀疑,这两个变量并不是同一个变量,并且这两个地址也不是同一个地址

事实也确实如此,这就是我们接下来要讲解的——进程地址空间

进程地址空间基础原理

我们先来看这样一张图

实际在我们的系统中,进程和内存之间,在逻辑上并不是紧紧相连的

我们进程中的数据,都是要先被放进一个叫做地址空间的地方上,而我们上面G_VAL的地址,其实就是这里的地址空间的地址

接着还有一个页表,页表负责映射地址空间的地址与物理内存的地址(比如左边是虚拟地址,我们在页表中就可以根据这个虚拟地址查询到某个变量在物理内存中具体被存放在哪里)

我们现在将上面这张图拆开来进行讲解:

今天我们有一个父进程,然后这个父进程有自己的进程地址空间,也有页表

现在父进程里面有一个变量,叫做G_VAL,值是100

注意,比如这个时候我们的代码实际是保存在物理内存中的

现在我们对这个父进程执行fork操作,那么就有了所谓子进程:

子进程也是一个进程,他也需要自己的进程地址空间和页表

子进程一开始什么都没有,但是他会直接将父进程的数据全部拷贝一遍(不包括代码,像代码这些只需要在物理内存保存一份,所有人都能看到就行了),包括变量G_VAL的值,在页表中与物理内存的映射,原原本本的全部拷贝一份(但是代码是没有拷贝的,因为这个是只读的,直接看父进程的就好了)

这个时候,我们的子进程就做到了,能和父进程“看到”一样的数据

G_VAL会在进程地址空间中有一个虚拟地址,经过页表映射,在物理内存上就能找到真实存放的位置

但是如果我们现在对G_VAL进行修改,那么写时拷贝就发生了,由于前面虽然是两个不同的进程,但是在物理内存上看到的本质上是同一个

这时候我们子进程想要修改这个变量,那么内存就只能再开辟一段空间,来存放一个新的变量,虽然这个变量也叫做G_VAL

但是,我们的虚拟地址并不会改变,因为没有改变的必要,页表倒是需要变一变,只不过虚拟地址那一部分不变,变的只是映射到物理内存的那个地址

所以这也就是为什么,我们在代码中看到的同一个地址,同一个变量,不同的值

本质上,那些都是虚拟地址,但是在内存中,这是两个完全不一样的值(如果没有修改值,没有发生写实拷贝的话那就是同一个值)

接下来我们可能会有两个疑问:

1. 子进程到了修改的时候才发生写实拷贝,效率怎么听起来会慢一点啊?

其实是不会的,因为如果这个变量没有改变的话,那我们就连拷贝都不需要,就算是发生了修改,那如果一开始就开辟空间,和要改了才开辟,其实就只是今天写作业和明天写作业的区别,到头来都是要写的

但是如果学校老师不检查的话,那甚至这个作业都可以不写(只是举例,思想上不倡导哈)

2. 为什么不在最开始的时候,将所有的数据都拷贝给子进程,不是说进程是相互独立的吗?

这个其实也没得说,像代码,环境变量等等,这些东西,大家看到的都是同一个,何必要全部拷贝呢?能省空间就省空间嘛,内存的空间也不是这么浪费的

区域划分的本质

如下图(其实还是上面的图的一部分):

我们会看到,进程地址空间是被划分成了一个个小位置的,比如栈区、堆区、静态区这些

先来说说为什么要这么分,他的意义是什么

试想一下,如果我们没有进程地址空间的话,那么我们的变量将会直接在内存上开辟,先不谈安全问题(比如越界访问),如果直接在内存上开辟,我们的变量在内存上的地址是否就要被记录下来,这样我们下一次才能找到这个变量并且进行使用

但是如果今天我不止一个变量,我有一百个,一千个变量,那么每一个变量我都只能一个一个记下来,这样,其实不是很好

但是现在我们有了进程地址空间中的区域划分,比如你这个变量是一个常量,是一个变量,是一个什么什么变量,你就放在对应的空间里面

这样我们下次要找的话,你这个变量就一定在某一段区域内,相对来说就好管得多

(当然这只是进程地址空间的其中一个好处)

我们来看看内核是怎么写的:

本质上,区域的划分就是存在PCB(task_struct)中的一个struct变量(mm_struct)中的一个个字段,仅此而已

如何理解进程地址空间

假如你是一个富豪,你有10亿美金的财产,现在你有五个私生子

你对每一个私生子都说,你有10个亿,等我不在了这钱全是你的

那么这时,每一个私生子都会想着,富豪只有他 / 她一个孩子,这时候你有用钱的需要,你就和富豪说,如果条件可行,那就运行,如果不对劲,那就驳回

对于内存也是,每一个进程都会认为自己面对的内存是完整的物理内存(进程地址空间)

这时候如果想要开辟物理空间了,那就提交申请给内存,这时候内存就会帮你开辟空间并将结果返回给你

意义是什么

第一、我们能保证进程之间是互相独立的

第二、能有效保护内存,如果说进程中有越界行为,他是碰不到内存的,在虚拟地址空间这里就被驳回了

第三、简化内存管理,进程看到的是连续的虚拟地址空间,实际物理内存可以零散分布(通过页表映射)

第四、高效的进程切换,比如10个进程运行同一程序,代码段只需一份物理内存,通过页表映射到各进程的相同虚拟地址

等等,还有很多原因这里就不一一列举了

越界访问的本质

现在再来看这个问题,就明朗多了

首先我们的变量地址都是被放在页表中一一映射的

现在我们突然来了一个不在这里面的地址,也就是越界访问

那么在页表里面查不到对应的信息,那么就会发现这个是错的,那么系统自然就会将这个请求直接驳回,然后执行某些操作,比如将这个进程直接kill掉,太危险了

进一步理解写时拷贝

首先我们还需要引入一个概念,那是和页表有关的,其实我们前面也学过,就是权限

是的,页表里面也是有权限的

所以我们现在看回这么一串代码:char* a = "hello world";

在我们之前的认知里,他是不能被修改的,因为他是一个常量

那么现在再来看,为什么不能修改?这是因为页表里面的权限,就直接设置了这个变量是只读的,如果你要写,那就直接驳回请求,所以我们才没办法修改

那么现在再来看看写时拷贝

首先,我们一开始所有的变量都是只读的

但是今天我们有一个变量G_VAL,现在我们对他进行修改,这时候就发生错误了

但是,操作系统面对错误之前,还会干一件事情,那就是先检查:

1. 是不是数据之前没放进物理内存里面(缺页中断)

2. 是否是需要写时拷贝

3. 异常处理

说实话这个是非常厉害的,现在我们的系统识别到了,你是想写时拷贝,所以就给你开空间,变页表等等,这也就是我们所谓写时拷贝的本质了

重谈 fork 返回值

现在我们再来看fork的返回值,相信你会变得非常熟悉:

来看这张图,里面的 id 不就是一个变量吗,在fork的逻辑中,当子进程被创造出来的时候,数据拷贝自原有的父进程

接着就是父进程id的值给一份给子进程

但是这个时候fork函数要return了,本质上,这就是写时拷贝

所以物理内存中又开辟了一段空间,给一个名字同样叫做id的变量放进了不同于另一个id的值

最后进程的页表中,关于物理地址映射的那一部分被修改

至此,我们的fork返回值,为什么可以同时给给两个值给 “同一个” 变量的话题,就讲完了

结语

这篇文章到这里就结束啦!!~( ̄▽ ̄)~*

如果觉得对你有帮助的,可以多多关注一下喔

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2394031.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

CTFHub-RCE 命令注入-过滤空格

观察源代码 代码里面可以发现过滤了空格 判断是Windows还是Linux 源代码中有 ping -c 4 说明是Linux 查看有哪些文件 127.0.0.1|ls 打开flag文件 我们尝试将空格转义打开这个文件 利用 ${IFS} 127.0.0.1|cat${IFS}flag_195671031713417.php 可是发现 文本内容显示不出来&…

Express教程【002】:Express监听GET和POST请求

文章目录 2、监听post和get请求2.1 监听GET请求2.2 监听POST请求 2、监听post和get请求 创建02-app.js文件。 2.1 监听GET请求 1️⃣通过app.get()方法,可以监听客户端的GET请求,具体的语法格式如下: // 1、导入express const express req…

【PostgreSQL 03】PostGIS空间数据深度实战:从地图服务到智慧城市

PostGIS空间数据深度实战:从地图服务到智慧城市 关键词 PostGIS, 空间数据库, 地理信息系统, GIS, 空间查询, 地理分析, 位置服务, 智慧城市, 空间索引, 坐标系统 摘要 PostGIS是PostgreSQL的空间数据扩展,它将普通的关系数据库转变为强大的地理信息系统…

HIT-csapp大作业:程序人生-HELLO‘s P2P

计算机系统 大作业 题 目 程序人生-Hello’s P2P 专 业 计算学部 学  号 2023111813 班 级 23L0518 学 生 鲁永哲 指 导 教 师 史先俊 计…

深入探讨redis:主从复制

前言 如果某个服务器程序,只部署在一个物理服务器上就可能会面临一下问题(单点问题) 可用性问题,如果这个机器挂了,那么对应的客户端服务也相继断开性能/支持的并发量有限 所以为了解决这些问题,就要引入分布式系统&#xff0c…

帕金森常见情况解读

一、身体出现的异常节奏​ 帕金森会让身体原本协调的 “舞步” 出现错乱。它是一种影响身体行动能力的状况,随着时间推进,就像老旧的时钟,齿轮转动不再顺畅,使得身体各个部位的配合逐渐失衡,打乱日常行动的节奏。​ …

清华大学发Nature!光学工程+神经网络创新结合

2025深度学习发论文&模型涨点之——光学工程神经网络 清华大学的一项开创性研究成果在《Nature》上发表,为光学神经网络的发展注入了强劲动力。该研究团队巧妙地提出了一种全前向模式(Fully Forward Mode,FFM)的训练方法&…

【android bluetooth 案例分析 04】【Carplay 详解 3】【Carplay 连接之车机主动连手机】

1. 背景 在前面的文章中,我们已经介绍了 carplay 在车机中的角色划分, 并实际分析了 手机主动连接车机的案例。 感兴趣可以 查看如下文章介绍。 【android bluetooth 案例分析 04】【Carplay 详解 1】【CarPlay 在车机侧的蓝牙通信原理与角色划分详解】…

C++学习-入门到精通【11】输入/输出流的深入剖析

C学习-入门到精通【11】输入/输出流的深入剖析 目录 C学习-入门到精通【11】输入/输出流的深入剖析一、流1.传统流和标准流2.iostream库的头文件3.输入/输出流的类的对象 二、输出流1.char* 变量的输出2.使用成员函数put进行字符输出 三、输入流1.get和getline成员函数2.istrea…

NW969NW978美光闪存颗粒NW980NW984

NW969NW978美光闪存颗粒NW980NW984 技术解析:NW969、NW978、NW980与NW984的架构创新 美光(Micron)的闪存颗粒系列,尤其是NW969、NW978、NW980和NW984,代表了存储技术的前沿突破。这些产品均采用第九代3D TLC&#xf…

使用 ssld 提取CMS 签名并重签名

拿SpringBoard的cms签名和entitlements.xml,对tihook.dylib进行重签名 工具来源:https://github.com/eksenior/ssld

大厂前端研发岗位PWA面试题及解析

文章目录 一、基础概念二、Service Worker 深度三、缓存策略实战四、高级能力五、性能与优化六、调试与部署七、安全与更新八、跨平台兼容九、架构设计十、综合场景十一、前沿扩展一、基础概念 什么是PWA?列举3个核心特性 解析:渐进式网页应用。核心特性:离线可用、类原生体…

第十四章 MQTT订阅

系列文章目录 系列文章目录 第一章 总体概述 第二章 在实体机上安装ubuntu 第三章 Windows远程连接ubuntu 第四章 使用Docker安装和运行EMQX 第五章 Docker卸载EMQX 第六章 EMQX客户端MQTTX Desktop的安装与使用 第七章 EMQX客户端MQTTX CLI的安装与使用 第八章 Wireshark工具…

腾讯云推出云开发AI Toolkit,国内首个面向智能编程的后端服务

5月28日,腾讯云开发 CloudBase 宣布推出 AI Toolkit(CloudBase AI Toolkit),这是国内首个面向智能编程的后端服务,适配 Cursor 等主流 AI 编程工具。 云开发 AI Toolkit旨在解决 AI 辅助编程的“最后一公里”问题&…

前端-不对用户显示

这是steam的商店偏好设置界面,在没有被锁在国区的steam账号会有5个选项,而被锁在国区的账号只有3个选项,这里使用的技术手段仅仅在前端隐藏了这个其他两个按钮。 单击F12打开开发者模式 单击1处,找到这一行代码,可以看…

WPF【10_2】数据库与WPF实战-示例

客户预约关联示例图 MainWindow.xaml 代码 <Window x:Class"WPF_CMS.MainWindow" xmlns"http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x"http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d"ht…

Cursor奇技淫巧篇(经常更新ing)

Dot files protection &#xff1a;Cursor当开启了Agent模式之后可以自动帮我们写文件&#xff0c;但是一般项目中的一些配置文件&#xff08;通常以.开头的&#xff09;都是非常重要性&#xff0c;为了防止Cursor在运行的过程中自己修改这些文件&#xff0c;导致风险&#xff…

Unity3D仿星露谷物语开发58之保存时钟信息到文件

1、目标 保存当前的时钟信息到文件中。 2、修改TimeManager对象 TimeManager对象添加组件&#xff1a;Generate GUID 3、修改SceneSave.cs脚本 添加1行代码&#xff1a; 4、修改TimeManager.cs脚本 添加&#xff1a; using System; 修改TimeManager类&#xff1a; 添加属…

lstm 长短期记忆 视频截图 kaggle示例

【官方双语】LSTM&#xff08;长短期记忆神经网络&#xff09;最简单清晰的解释来了&#xff01;_哔哩哔哩_bilibili . [short,input]*[2.7,1.63]b5.95 换参数和激活函数 tan激活函数输出带正负符号的百分比 tanx公式长这样&#xff1f; 潜在短期记忆 前几天都是乱预测&#xf…

Spring Advisor增强规则实现原理介绍

Spring Advisor增强规则实现原理介绍 一、什么是 Advisor&#xff1f;1. Advisor 的定义与本质接口定义&#xff1a; 2. Advisor 的核心作用统一封装切点与通知构建拦截器链的基础实现增强逻辑的灵活组合 二. Sprin当中的实现逻辑1 Advisor 接口定义2 PointcutAdvisor 接口定义…