【Linux 学习计划】-- 进程地址空间
目录
进程地址的引入
进程地址空间基础原理
区域划分的本质
如何理解进程地址空间
越界访问的本质
进一步理解写时拷贝
重谈 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返回值,为什么可以同时给给两个值给 “同一个” 变量的话题,就讲完了
结语
这篇文章到这里就结束啦!!~( ̄▽ ̄)~*
如果觉得对你有帮助的,可以多多关注一下喔
相关文章:

【Linux 学习计划】-- 进程地址空间
目录 进程地址的引入 进程地址空间基础原理 区域划分的本质 如何理解进程地址空间 越界访问的本质 进一步理解写时拷贝 重谈 fork 返回值 结语 进程地址的引入 我们先来看一段代码: 首先我们可以看到,父进程和子进程是可以同时可以看到一个变量…...
告别重复 - Ansible 配置管理入门与核心价值
告别重复 - Ansible 配置管理入门与核心价值 还记得我们在 SRE 基础系列中反复强调的“减少琐事 (Toil)”和“拥抱自动化”吗?想象一下这些场景: 你需要部署一个新的 Web 服务集群,每台服务器都需要安装 Nginx、配置防火墙规则、同步 Web 内容、启动服务……手动操作不仅耗时…...
3D Gaussian splatting 04: 代码阅读-提取相机位姿和稀疏点云
目录 3D Gaussian splatting 01: 环境搭建3D Gaussian splatting 02: 快速评估3D Gaussian splatting 03: 用户数据训练和结果查看3D Gaussian splatting 04: 代码阅读-提取相机位姿和稀疏点云3D Gaussian splatting 05: 代码阅读-训练整体流程3D Gaussian splatting 06: 代码…...

CTFHub-RCE 命令注入-过滤空格
观察源代码 代码里面可以发现过滤了空格 判断是Windows还是Linux 源代码中有 ping -c 4 说明是Linux 查看有哪些文件 127.0.0.1|ls 打开flag文件 我们尝试将空格转义打开这个文件 利用 ${IFS} 127.0.0.1|cat${IFS}flag_195671031713417.php 可是发现 文本内容显示不出来&…...
卫生间改造翻新怎么选产品?我在瑞尔特找到了解决方案
在一场打掉重来的卫生间翻新改造中,最令人头疼的,从来都不是瓷砖、吊顶这类“看得见”的工序,而是那些每天都在用、但选错一次就要懊悔好多年的卫浴产品。从功能到体验,从老人适配到美学搭配,这事真不是买个贵的就够了…...
C++ list数据删除、list数据访问、list反转链表、list数据排序
list数据删除,代码见下 #include<iostream> #include<list>using namespace std;void printList(const list<int>& l) {for (list<int>::const_iterator it l.begin(); it ! l.end(); it) {cout << *it << " "…...

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…...
mysql安装教程--笔记
一、Windows 系统安装 方法1:使用 MySQL Installer(推荐) 1. 下载安装包 访问 MySQL 官网下载页面,选择 MySQL Installer for Windows。 2. 运行安装程序 双击下载的 .msi 文件,选择安装类型: ◦ Developer…...
C++ 观察者模式:设计与实现详解
一、引言 在现代软件开发中,组件间的交互与通信是系统设计的核心挑战之一。观察者模式(Observer Pattern)作为一种行为设计模式,提供了一种优雅的解决方案,用于实现对象间的一对多依赖关系。本文将深入探讨 C++ 中观察者模式的设计理念、实现方式及其应用场景。 二、观察…...

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

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

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

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

清华大学发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…...

使用 ssld 提取CMS 签名并重签名
拿SpringBoard的cms签名和entitlements.xml,对tihook.dylib进行重签名 工具来源:https://github.com/eksenior/ssld...
前端基础之《Vue(17)—路由集成》
一、页面应用程序分类 1、单页面应用程序(SPA) 通过路由系统把组件串联起来的并且只有一个根index.html页面的程序,叫做单页面应用程序。 2、多页面应用程序(MPA) 整个应用程序中,有多个.html页面。每次用…...

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

第十四章 MQTT订阅
系列文章目录 系列文章目录 第一章 总体概述 第二章 在实体机上安装ubuntu 第三章 Windows远程连接ubuntu 第四章 使用Docker安装和运行EMQX 第五章 Docker卸载EMQX 第六章 EMQX客户端MQTTX Desktop的安装与使用 第七章 EMQX客户端MQTTX CLI的安装与使用 第八章 Wireshark工具…...
element ui 表格 勾选复选框后点击分页不保存之前的数据问题
element ui 表格 勾选复选框后点击分页不保存之前的数据问题 给 el-table上加 :row-key"getRowKey"给type“selection” 上加 :reserve-selection"true"...
DataAgent产品经理(数据智能方向)
DataAgent产品经理(数据智能方向) 一、核心岗位职责 AI智能体解决方案设计 面向工业/政务场景构建「数据-模型-交互」闭环,需整合多源异构数据(如传感器数据、业务系统日志)与AI能力(如大模型微调、知识图…...

腾讯云推出云开发AI Toolkit,国内首个面向智能编程的后端服务
5月28日,腾讯云开发 CloudBase 宣布推出 AI Toolkit(CloudBase AI Toolkit),这是国内首个面向智能编程的后端服务,适配 Cursor 等主流 AI 编程工具。 云开发 AI Toolkit旨在解决 AI 辅助编程的“最后一公里”问题&…...
华为计试——刷题
判断两个IP是否属于同一子网 题目:给定一个子网掩码和两个 IP 地址,判断这两个 IP 地址是否在同一个子网中。 思路:首先,判断这个 IP 地址和子网掩码格式是否正确,不正确输出 ‘1’,进而结束;…...
【AI-安装指南】Redis Stack 的安装与使用
目录 一、Redis Stack 的介绍 二、安装方式 2.1 安装 2.2 添加依赖 2.3 设置配置信息 2.4 Redis 添加向量数据 2.5 查询向量数据 一、Redis Stack 的介绍 传统的 Redis 服务是不能存储向量的,因此我们需要首先安装 Redis Stack,而 Windows 电脑安 装 Redis Stack,官方…...
LeetCode Hot100(矩阵)
73. 矩阵置零 这边提供nm的做法以及更少的思路,对于nm的做法,我们只需要开辟标记当前行是否存在0以及当前列是否存在0即可,做法如下 class Solution {public void setZeroes(int[][] matrix) {int arr[]new int[matrix.length];int brr[]ne…...
spark在执行中如何选择shuffle策略
目录 1. SortShuffleManager与HashShuffleManager的选择2. Shuffle策略的自动选择机制3. 关键配置参数4. 版本差异(3.0+新特性)5. 异常处理与调优6. 高级Shuffle服务(CSS)1. SortShuffleManager与HashShuffleManager的选择 SortShuffleManager:默认使用,适用于大规模数据…...

前端-不对用户显示
这是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…...