【进程概念④】:进程地址空间(虚拟内存与物理内存)
【进程概念④】:进程地址空间(虚拟内存与物理内存)
- 一.进程地址空间
- 二.分页与虚拟地址
- ①.what
- ②.how
- ③.why
- 三.页表细节
- ①.标志位
- ②.缺页中断
- 四.总结意义
一.进程地址空间
你觉得我们代码中写的数据都在哪存储着呢?
在内存里存着!确实是在内存里存储着,那你知道数据存在内存的哪里呢?
你以前肯定听过栈,堆,静态区等等的。都是在"内存"上划分的。

比如局部变量是在栈上开辟的,动态申请的空间是在堆区申请的,全局变量是在全局区(这里又分成初始化数据和未初始化数据)代码都是存在代码段的。
对于栈呢,它是向下增长,也就是向地址减少的地方增长的;对于堆呢,它是向上增长,也就是向地址增长的方向增长的。
所以在我们没有学习进程地址空间时,我们对于内存的印象就是如上图所示。而学习进程地址空间后,你就会发现其实这个并不是真正的"内存"。
理解进程地址空间,我们先理解一下下面这个问题:
【问题】我们知道fork()创建进程时会返回两个值,为什么同一个变量可以接受两不同的值呢?
#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){ //child子进程g_val=100;//将全局变量改成100;printf("child[%d]: %d : %p\n", getpid(), g_val, &g_val);}else{ //parent父进程printf("parent[%d]: %d : %p\n", getpid(), g_val, &g_val);}sleep(1);return 0;
}

我们在全局定义一个变量g_val.并初始化为0.
然后利用fork()函数创建两个进程,一个为子进程,一个为父进程,子进程先执行,在子进程中将全局变量修改成g_val修改成100.并打印它的值和地址。在父进程中修改全局变量的值,打印它的值和地址。最后结果显示,子进程和父进程中的全局变量值并不一样,而地址确实一样的,这是为什么呢?
我们可以猜想:
1.变量内容不相同,父子进程中输入的变量肯定不是同一个变量。
2.但是父子进程中,变量的地址却又相同,这说明这个地址肯定不是物理地址,因为物理地址只能一对一,不存在一对多的情况。
其实这里的地址是虚拟地址,在Linux中,我们用c/C++语言所看到的地址都是虚拟地址,都不是物理地址,物理地址用户是看不到的。
二.分页与虚拟地址
其实呢进程并不是直接与物理内存进行交互的,中间还存在着一个叫做进程地址空间的对象。进程地址空间其实就是虚拟内存,而物理内存才是真正的内存,除了进程地址空间外,中间还存在一个叫页表的对象,它是用来将虚拟地址转换映射成物理地址的。页表中其实有很多标识位,比如权限位和判断位等等。最主要还是它可以将虚拟地址映射到物理地址上去,页表的左边存的都是虚拟地址,页表的右边则是存着物理地址。这就形成了映射。当进程访问内存时,先访问的是虚拟内存,然后才是根据页表映射转换到物理内存。

当使用fork()创建子进程时,子进程也需要进程地址空间,而子进程的进程地址空间是继承父进程的,也就是直接从父进程那拷贝过来的。
子进程的页表其实也是从父进程那拷贝过来的,所以父子进程默认情况下,数据和代码指向都是一样的,也就印证了父子代码共享,数据一般也是共享的,除非发生写实拷贝。

好的,我们现在再转回到问题上去:为什么fork()返回的两个值可以存在同一个变量里?为什么父子进程的变量值不相同,但地址却相同呢?
首先我们要确定的是,他们这里面发生了写入数据导致发生写实拷贝了。fork()返回返回值时是不是写入?改变全局变量的值是不是写入?
那么写时拷贝发生了什么呢?
写时拷贝,父子进程先写入的就会将要访问的数据拷贝一份,重新开辟内存创建变量。所以关键在于重新开辟了一块空间了。
这时子进程的物理地址就不再指向父进程原来的变量位置,而是指向一块新开辟的空间了。但是这个写时拷贝的过程,并不影响进程虚拟地址。
所以我们就可以知道为什么父子进程中同一个变量值不同了,是因为变量的物理内存不同,它们的地址却相同,是因为写时拷贝不影响虚拟内存。

①.what
什么是进程地址空间呢?

什么是32位机器呢?就是它有32个总线。每一根地址总线只有0,1表示。那么可以表示的范围就是0–2^32种了。而这就是该机器下所能表示的内存范围,至于地址空间是什么,就是地址总线排列组合形成的地址范围,能访问的最大范围,也就是一段数据(地址)的范围。
②.how
如何理解地址空间上的区域划分呢?区域又是如何进行划分的呢?

我们可以假设有一块连续空间,被小胖和小芳两个人共同使用,但是小胖总是喜欢跑到小芳的位置上吃零食,睡觉,小芳这能忍吗?这当然不能忍了。所以小芳就提出划分区域,定出一个三八线出来,不给小胖逾越。那么你想一想应该如何帮助小芳进行区域的划分呢?
我们可以直接定义一个桌面区域结构体,它里面包含着四个变量,小胖的起始位置和小胖的终点位置,小芳的起始位置和小芳的终点位置。这里通过这个结构体对象,我们就可以对该区域进行划分,小芳想要公平公正一些就各自一人一般的区间,谁也不能逾越。
所以结构体对象就可以这样定义:
struct desk_area justic{ 1,50,51,100 };
所以对于每一个进程来说,除了要有PCB外,还需要进程地址空间。
在进程创建时,操作系统处理创建一个PCB对象给进程,还要创建一个进程地址空间对象给进程。并且操作系统还要对这个地址空间进行管理,至于如何管理呢?先描述,再组织!

操作系统会像上面一样首先会对进程地址空间进行描述,将空间区域的划分边界变量确定下来。操作系统不是直接在PCB里创建进程地址空间对象,而是在PCB里存储一个指向进程地址空间的指针,然后再利用数据结构进行管理。
1.其实所谓的进程地址空间,本质上就是一个描述进程可视范围的大小,就是进程可以看到内存的范围。
2.地址空间里会存在区域的划分,划分的手段,就是将线性地址发个成不同区的start和end。
3.进程空间本质也是内核的一个数据结构对象,类似于PCB。地址空间也是需要被操作系统管理的。

在进程PCB里存着一个指针,叫做struct mm_struct的对象指针。这个对象指针就是指向进程地址空间的。

③.why
为什么要有进程地址空间呢?
在这里我们对进程的理解更深入了,进程的概念仍然是:内核数据结构+自己写的代码和数据。只不过这里的内核数据结构
除了PCB对象外,还有进程地址空间对象。
在没有进程地址空间以前,进程都是直接访问物理地址的,这很危险,进程管理和内存管理两个直接出现了强耦合。当内存管理出现了问题,进程就挂了,比如如果是越界访问,进程就直接挂掉,但就怕有人将物理地址空间修改了,内容改变了,这可能会影响其他进程。

而现在呢,有了进程空间地址,我们不再直接跟物理内存进行访问,而是通过虚拟内存进行访问,如果出现了问题,虚拟内存的机制会进行拦截除了的,并不会到达物理内存,这样就大大的保护了物理内存了。
1.所以进程地址空间可以让我访问内存时,增加一个转换的过程,在这个转换的过程中,可以对我们的寻址请求进行审查,一旦出现异常访问,直接拦截,该请求不会到达物理内存,保护物理内存。
2.可以让进程一统一的视角看待内部。因为物理内存是没有区域划分的,是可以随意任何地方开辟空间的,而虚拟内存则是划分区域的;最后可以让无序变有序。
3.减少了强耦合,一旦内存管理出现问题,会影响其他进程。
三.页表细节
①.标志位
页表是在哪呢?在CPU的一个叫cr3的寄存器里,里面存储着页表的起始地址。
我们要理解当进行需要使用页表时,肯定表面该进程正在运行使用中,那么肯定在CPU上运行着,所以进程直接通过CPU上的寄存器就可以找到该进程的页表。
在深入理解页表之前,我们先理解一个问题
【问题】为什么只读区的数据只读不给写的?静态成员为什么不能修改呢?代码是只读的?为什么呢?
对于物理内存来说,没有只读概念,都是可访问的,所以实现这个操作的关键在页表。
在页表中除了虚拟内存映射物理内存外,还有一个标识位。
表示该内存是否可以读写,r表示只读,rw表示可读可写。
所以对于代码区域的或者静态区的虚拟内存确实映射到物理内存上了,但页表还给它进行了标识r表示只读。这样该数据就只能是只读状态不可写。

②.缺页中断
我们知道进程挂起时,会将进程的代码和数据先放入磁盘中省出空间,给CPU使用,那么我们如何确定进程的代码和数据被放入磁盘里了呢?

对于虚拟内存,地址都可以先将加载到页表里,而物理内存可以先不加载进去,然后页表里存在一个标志位,用来表示该物理内存是否存在,0表示不存在,1表示存在。
所以当CPU需要访问某个数据时,首先会根据页表从虚拟地址转换到物理地址,如果发现页表里没有加载该数据的物理地址,页表里的标识位也为0.操作系统会给这个数据申请内存,然后将申请的内存地址加载到页表里,并将标识位改成1,然后CPU再重新访问页表映射到物理地址。这时就可以正常访问数据了,这个过程叫做页表中断。

所以对于进程来说,一开始没有数据加载到内存里,也是可以创建PCB内核数据结构的,等当真正访问数据时再将数据加载进来。
并且就算程序运行起来了,数据加载进来了,也不代表所有的数据都加载进来。
写时拷贝的本质也就是发生了缺页中断。
四.总结意义
当发生缺页中断时,内存会重新申请,页表的物理地址会被填充内存的释放等过程跟进程是没有关系的,进程不需要关系这些问题。
进程只需向虚拟内存申请空间,释放空间。如果页表中的物理地址不存在,就会发生缺页中断自动调用内存管理的功能,去向内存中申请空间。
所有进程地址空间和页表的存在,使得进程管理根本不需要关心内存管理。

1.总结进程地址空间意义:
2.什么是统一的视角看待内存呢?
3.并且我们可以从更深层去阐明进程之间为什么存在着独立性:虚拟地址可以完全一样,但物理地址不同!
4.进程地址空间的存在使得物理内存不再被看见!
相关文章:
【进程概念④】:进程地址空间(虚拟内存与物理内存)
【进程概念④】:进程地址空间(虚拟内存与物理内存) 一.进程地址空间二.分页与虚拟地址①.what②.how③.why 三.页表细节①.标志位②.缺页中断 四.总结意义 一.进程地址空间 你觉得我们代码中写的数据都在哪存储着呢? 在内存里存着࿰…...
C语言内存四分区
四个区域:代码区,全局区,栈区,堆区 ①代码区 存放所写代码,二进制内容 ②全局区(又分data区和bss区) 存放全局变量,静态变量,常量 data区:已经初始化的全局变…...
数据可视化报表分享:区域管理驾驶舱
在零售数据分析中,区域管理驾驶舱报表是用来分析企业运营数据,以制定销售策略和提高利润。因此这张报表需要整合大量数据,数据整合、分析、指标计算的工作量极大,在讲究高效率、高度及时性的大数据时代,BI数据可视化分…...
解决pip安装包后但是Pycharm检测不到
首先要知道python找包的原理:原理 之后把一下代码打印一下: import sys print(sys.executable)# /usr/bin/python2 print(sys.path)# [/usr/lib/python2.7, /usr/lib/python2.7/dist-packages, /usr/local/lib/python2.7/dist-packages] print(sys.prefi…...
折纸问题
折纸的次数 —— 从上到下的折痕 本质上是中序遍历的问题,因为每一次在已有的折痕后折的时候,当前折痕上的折痕一定为凹,当前折痕下的折痕一定为凸 。实际模拟了一个不存在的二叉树结构的中序遍历。 注:折纸折几次整颗二叉树就有…...
mysql-面试50题-2
一、查询数据 学生表 Student create table Student(SId varchar(10),Sname varchar(10),Sage datetime,Ssex varchar(10)); insert into Student values(01 , 赵雷 , 1990-01-01 , 男); insert into Student values(02 , 钱电 , 1990-12-21 , 男); insert into Student v…...
FoLR:Focus on Local Regions for Query-based Object Detection论文学习笔记
论文地址:https://arxiv.org/abs/2310.06470 自从DETR问询式检测器首次亮相以来,基于查询的方法在目标检测中引起了广泛关注。然而,这些方法面临着收敛速度慢和性能亚优等挑战。值得注意的是,在目标检测中,自注意力机制…...
【QT开发(15)】QT在没有桌面的系统中可以使用
在没有桌面的系统中,可以使用QT库。QT库可以在没有图形用户界面(GUI)的环境中运行,例如在服务器或命令行终端中。 这样就可利用Qt的: 对象模型,信号和槽容器类多线程和多进程网络编程 等...
『heqingchun-Qt的艺术-优雅界面设计开发』
Qt的艺术-优雅界面设计开发 效果图 一、新建Qt窗口工程 二、准备资源文件 1.图标资源 链接: 图标资源 2.Qss资源 链接: Qss资源 三、设计开发 项目源码链接: CSDN资源...
webGL编程指南 第四章 平移+旋转.RotatdTanslatedTriangle.html
我会持续更新关于wegl的编程指南中的代码。 当前的代码不会使用书中的缩写,每一步都是会展开写。希望能给后来学习的一些帮助 git代码地址 :git 本篇文章将把旋转和平位移结合起来,因为矩阵的不存在交换法则 文章中设计的矩阵地址在这里…...
使用canvas实现时间轴上滑块的各种常用操作(仅供参考)
一、简介 使用canvas,模拟绘制时间轴区域,有时间刻度标尺,时间轴区域上会有多行,每行都有一个滑块。 1、时间刻度标尺可以拖动,会自动对齐整数点秒数,最小步数为0.1秒。 2、滑块可以自由拖动,…...
Netty优化-扩展自定义协议中的序列化算法
Netty优化-扩展自定义协议中的序列化算法 一. 优化与源码1. 优化1.1 扩展自定义协议中的序列化算法 一. 优化与源码 1. 优化 1.1 扩展自定义协议中的序列化算法 序列化,反序列化主要用在消息正文的转换上 序列化时,需要将 Java 对象变为要传输的数据…...
【Java网络编程】二
本文主要介绍了传输层的UDP协议和TCP协议,以及在Java中如何通过Socket套接字实现网络编程(内附UDP和TCP版本的回显服务器代码) 一.网络通信 网络编程,就是写一个应用程序,让这个程序可以使用网络通信,这里就…...
通过IP地址可以做什么
通过IP地址可以做很多事情,因为它是互联网通信的基础之一。本文将探讨IP地址的定义、用途以及一些可能的应用。 IP地址的用途 1. 设备标识:IP地址用于标识互联网上的每个设备,这包括计算机、服务器、路由器、智能手机等。它类似于我们日常生…...
前端 CSS 经典:clip、clip-path
1. clip 1.1 clip: auto | inherit | rect auto:默认,不裁剪 inherit:继承父级 clip 属性 rect:规则四边形裁剪 1.2 clip: rect(top, right, bottom, left) 注意: 1.裁剪只对 fixed 和 absolute 的元素有效。 2.top&…...
android 如何判断已配对的蓝牙是否打开了互联网访问开关
最近遇到一个需求,要判断已配对的蓝牙是否打开了互联网访问的开关。 经查看源码,得出以下方法。 1. 首先要判断蓝牙是否打开 2. 已打开的蓝牙是否已配对 3. 验证是否真正打开 /*** 是否打开蓝牙互联网访问*/SuppressLint("MissingPermission&quo…...
在Linux上实现ECAT主站
在Linux上实现ECAT主站 引言介绍EtherCATSOEM 使用下载ECAT主站编译 引言 EtherCAT由一个主站设备和多个从站设备组成。主站设备使用标准的以太网控制器,具有良好的兼容性,任何具有网络接口卡的计算机和具有以太网控制的嵌入式设备都可以作为EtherCAT的…...
Spring Cloud之服务熔断与降级(Hystrix)
目录 Hystrix 概念 作用 服务降级 简介 使用场景 接口降级 服务端服务降级 1.添加依赖 2.定义接口 3.实现接口 4.Controller类使用 5.启动类添加注释 6.浏览器访问 客户端服务降级 1.添加依赖 2.application.yml 中添加配置 3.定义接口 4.Controller类使用 …...
HashMap 哈希碰撞、负载因子、插入方式、扩容倍数
HashMap 怎么解决的哈希碰撞问题? 主要采用了链地址法。具体来说: 每个哈希桶不仅存储一个键-值对,而是存储一个链表或树结构。这样,具有相同哈希值的键-值对可以被存储在同一个哈希桶中,并通过链表或树结构来解决碰…...
【Unity3D】Unity与Android交互
1 Unity 发布 apk 1.1 安装 Android Build Support 在 Unity Hub 中打开添加模块窗口,操作如下。 选择 Android Build Support 安装,如下(笔者这里已安装过)。 创建一个 Unity 项目,依次点击【File→Build Settings→…...
LayerDivider终极指南:AI智能图像分层工具完全解析
LayerDivider终极指南:AI智能图像分层工具完全解析 【免费下载链接】layerdivider A tool to divide a single illustration into a layered structure. 项目地址: https://gitcode.com/gh_mirrors/la/layerdivider 你是否曾面对复杂的插画作品,需…...
PP实施经验分享(22)——(ECC版本)生产版本\BOM\工艺路线选择策略与批量大小优化实践
1. ECC版本下生产版本的选择逻辑 在SAP ECC系统中,生产版本的选择逻辑与S4版本存在显著差异。我经历过一个汽车零部件制造项目,当时客户就遇到了生产版本选择混乱的问题。他们原先使用的是S4系统,切换到ECC后发现很多配置需要重新调整。 物料…...
烽火HG680-MC全分区TTL救砖指南:从黑屏到流畅运行的完整解决方案
1. 烽火HG680-MC救砖前的准备工作 遇到黑屏、卡LOGO的烽火HG680-MC盒子别急着扔,TTL线刷能救回90%的"砖机"。我经手过上百台同型号设备,先说说你手头要准备的"救命工具包": 硬件三件套:CH340G芯片的TTL转USB模…...
3个技巧:如何用开源工具彻底解决Beyond Compare授权难题
3个技巧:如何用开源工具彻底解决Beyond Compare授权难题 【免费下载链接】BCompare_Keygen Keygen for BCompare 5 项目地址: https://gitcode.com/gh_mirrors/bc/BCompare_Keygen 当Beyond Compare 5的30天评估期结束后,用户常常会遇到"评估…...
如何快速上手LeaguePrank:英雄联盟段位修改工具完整实战指南
如何快速上手LeaguePrank:英雄联盟段位修改工具完整实战指南 【免费下载链接】LeaguePrank 项目地址: https://gitcode.com/gh_mirrors/le/LeaguePrank 还在为英雄联盟单调的段位显示感到无聊吗?LeaguePrank是一款开源工具,让你轻松修…...
GTE-Pro语义检索系统国际化支持:中英混合Query与多语言文档联合检索
GTE-Pro语义检索系统国际化支持:中英混合Query与多语言文档联合检索 1. 引言:当搜索不再受限于语言 想象一下,你在一家跨国公司的技术文档库里查找资料。你的脑海里蹦出一个问题:“How to configure the 负载均衡器 for high av…...
Ostrakon-VL处理网络协议:从数据包捕获文件可视化网络流量
Ostrakon-VL处理网络协议:从数据包捕获文件可视化网络流量 1. 网络流量分析的痛点与机遇 网络工程师每天都要面对海量的网络数据包,传统的分析工具虽然功能强大,但存在几个明显痛点: 数据量大:一个中等规模企业的日…...
手把手改造Ruoyi-vue-plus权限体系:给多租户增加动态数据权限控制
深度定制Ruoyi-vue-plus多租户数据权限:从架构设计到前端适配全解析 在当今企业级应用开发中,多租户系统已成为SaaS服务的标配,而数据权限控制则是确保租户间数据隔离的核心机制。Ruoyi-vue-plus作为国内流行的快速开发框架,其原生…...
CYBER-VISION零号协议Markdown文档大师:替代Typora的智能写作体验
CYBER-VISION零号协议Markdown文档大师:替代Typora的智能写作体验 如果你和我一样,每天都要和Markdown文档打交道,那你肯定知道那种感觉:面对一个空白文档,脑子里有想法,但就是敲不出满意的句子࿱…...
新一代指控系统依然是:人机环
AI是强大的“赋能器”和“加速器”,但指挥的艺术、责任和最终决断必须由人掌握。基于俄乌、美以伊博弈的案例,构建新一代“人机环境融合”体系化指控系统的具体实践路径已经清晰。AI的定位:从“自动化”到“智能化辅助”美军Maven系统&#x…...




