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

【Linux】虚拟地址空间,页表,物理内存

目录

进程地址空间,页表,物理内存

什么叫作地址空间?

如何理解地址空间的区域划分?

地址空间结构体

为什么要有地址空间?

页表

cr3寄存器

权限标记位

位置标记位

其他


每个存储单元是一个字节,一共有2^32个字节,大概有4G。
栈往下走,堆往上走。
static修饰的局部变量编译的时候会被编译到全局数据区。

如下图,父子进程访问同一个变量,子进程修改了一下变量,如何做到同一个地址,却读到了不同的内容?

答:因为这个地址不是物理地址,这个地址是虚拟地址或线性地址,平时语言用的地址都是虚拟地址。

进程地址空间,页表,物理内存

创建父进程时,系统会创建对应的PCB,进程对应的代码和数据会加载到内存,同时PCB还能找到代码和数据。

创建父进程

实际上并没有这么简单,创建父进程后,有了PCB后,系统还要为该进程创建进程地址空间,页表。

进程用的地址是进程地址空间里面的虚拟地址。

页表存放的是虚拟地址和物理地址的映射。

假设定义一个变量,那么系统要在物理内存中为这个变量开辟一个空间,这个变量有一个物理地址和一个虚拟地址,进程通过页表将虚拟地址转成物理地址实现访问。

创建子进程

如果这个父进程创建了一个子进程,为了体现进程独立性,子进程会拷贝父进程的PCB,进程地址空间,页表。

子进程的PCB大部分值和父进程一样,少部分需要自己修改。

进程地址空间和父进程一样,所以虚拟地址也一样。

页表和父进程一样,所以能实现数据共享,代码共享,因为虚拟地址,物理地址和父进程都一样。

字进程修改数据

当子进程要修改数据时,如果系统发现这个位置的数据是和父进程共享的,那么此时系统会自动进行写时拷贝,也就是在物理内存上另开辟一个新的空间,然后当前值拷贝过去,然后修改页表对应的物理地址,此时再允许你写入,这个过程不会影响虚拟地址。       

什么叫作地址空间?

地址总线排列组合形成的范围就是地址空间,在32位计算机中,地址总线有32位,从全0到全1有2的32次方种组合,每一种组合可以标识一个字节,所以这个空间大约有4G。

如何理解地址空间的区域划分?

假设小胖和小花是同桌,中间有一条38线划分了他们的区域,只需记录这块区域的起始位置和结束位置就可以划分这段区域。

划分区域的变大变小只需要调整起始位置或结束位置的数值即可。

小胖的空间范围是1到50,他可以访问范围内的所有数据。在地址空间范围内,每一个最小单位都有自己的地址,都可以被小胖直接使用。

所以,进程地址空间本质是描述该进程可使用的范围空间大小,地址空间存在各种区域划分,划分方法是记录该区域的起始和结束位置。

地址空间结构体

地址空间本质是系统的一个结构体对象,类似PCB,地址空间结构体存放的是区域的起始结束位置。

进程创建时,系统会创建PCB,也会创建一个虚拟地址空间对象,PCB有个指针可以找到这个对象。

为什么要有地址空间?

物理地址空间只有一个,虚拟地址空间每个进程都有一个,进程申请空间系统就给,每个进程都以为自己拥有全部的地址空间。
第一个原因:虚拟地址空间可以让进程以统一的视角看待内存。
第二个原因:虚拟地址空间可以让进程访问内存时有一个虚拟地址转化物理地址的过程,在这个过程可以对寻址请求进行审查,异常访问直接拦截,从而保护了物理内存。  
第三个原因:地址空间和页表将进程管理模块和内存管理模块解耦。

页表

cr3寄存器

CPU有个cr3寄存器,里面保存着页表的起始地址。进程切换时会把这个地址带走,所以不用担心找不到自己的页表。

权限标记位

页表还有第三个位置是标记位,代表访问区域的读写权限,如果你向一个只读区域进行写操作就会被拦截。
 

所以说为什么代码段,字符常量区是只读的,难道第一次写入不是写入吗?
因为写入物理内存时没有读写要求,而当你用虚拟地址访问时,页表有标志位判断该位置的读写权限。

位置标记位

页表还有一个标志位,表示对应的代码和数据在磁盘还是在内存。当我们读取虚拟地址时,先看标志位,如果在内存就直接访问物理地址,如果在磁盘就会触发缺页中断,系统会把对应的数据加载到内存里,并建立虚拟地址和物理地址的映射,然后重新访问。

惰性加载方式,虚拟地址先填上,物理地址不填,需要时再填上。

所以,创建进程时,系统先给你创建PCB,虚拟地址空间,页表,但是对应的代码和数据不给你加载到内存,等你要访问时再进行缺页中断惰性加载,从而实现边使用边加载。

其他

命令行参数的空间在栈的上面。

父子进程虚拟地址一样,物理地址不同,修改数据只会改变页表右侧的地址。

http://www.lryc.cn/news/487364.html

相关文章:

  • C++ 并发专题 - 线程安全的单例模式
  • Spring Boot汽车世界:资讯与技术的交汇
  • 力扣 LeetCode 541. 反转字符串II(Day4:字符串)
  • Django5 2024全栈开发指南(一):框架简介、环境搭建与项目结构
  • Uniapp运行环境判断和解决跨端兼容性详解
  • Linux设置开机自动执行脚本 rc-local
  • 驱动开发小问题 -记录一下
  • 学习笔记018——若依框架数据权限功能的实现
  • Nginx文件下载服务器搭建
  • AWD脚本编写_1
  • HarmonyOS 如何获取设备信息(系统、版本、网络连接状态)
  • 2411rust,1.80
  • FPGA 第6讲 简单组合逻辑多路选择器
  • Android Studio开发学习(五)———LinearLayout(线性布局)
  • 大模型(LLMs)RAG 版面分析------文本分块面
  • Web3游戏先锋 Big Time Studios 重磅推出 $OL 通证,赋能 Open Loot 游戏平台
  • Linux—ln(link files)命令使用方法(How to create links on Linux)
  • 学习日记_20241110_聚类方法(K-Means)
  • 解决Oracle DECODE函数字符串截断问题的深度剖析20241113
  • 开源模型应用落地-语音转文本-whisper模型-AIGC应用探索(二)
  • PHP框架 单一入口和多入口以及优缺点
  • PhpSpreadsheet导出图片
  • AI 提示词(Prompt)入门 十:最佳实践|详细询问,提供细节!
  • web应用安全和信息泄露预防
  • 《人工智能深度学习的基本路线图》
  • 基于Java Springboot宠物猫售卖管理系统
  • 力扣-Hot100-链表其三【算法学习day.36】
  • iOS逆向入门:使用theos注入第三方依赖库
  • JavaScript 原型
  • 力扣 LeetCode 20. 有效的括号(Day5:栈与队列)