【操作系统笔记五】内存布局内存映射

news2024/11/20 18:36:28

虚拟内存布局

在这里插入图片描述

虚拟地址空间大小:

  • 32位虚拟地址空间 [0 ~ 2^32 - 1] 总共4GB
  • 64位虚拟地址空间 [0 ~ 2^64 - 1] 总共16 777 216TB

在这里插入图片描述

不管是运行在用户态还是内核态,都需要使用虚拟地址,这是因为计算机硬件要求的,CPU要经过地址转换得到最终的物理地址,软件必须服从硬件的规定。

在这里插入图片描述
在这里插入图片描述

内核态的虚拟空间和某一个程序没有关系,所有程序通过系统调用进入到内核之后,看到的虚拟地址空间都是一样的。

在这里插入图片描述

在这里插入图片描述

  • 32 位虚拟地址空间中,[0x0000 0000, 0xBFFF FFFF] 的 3GB 空间用作用户态,是每一个应用程序可以使用的虚拟地址范围,[0xC000 0000, 0xFFFF FFFF] 的 1GB 空间用作内核态,是给操作系统内核使用的虚拟地址范围

  • 每个用户程序都使用相同的虚拟地址空间 [0x0000 0000, 0xBFFF FFFF],每个内核程序也使用相同的虚拟地址空间 [0xC000 0000, 0xFFFF FFFF]

  • 64 位虚拟地址空间中,低 128T 虚拟地址空间被用作用户态,高 128T 虚拟地址空间被用作内核态,中间留有空洞

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

用户态虚拟内存布局,从上往下分别是:

  • 栈(stack)

  • mmap内存映射区

  • 运行时堆区(heap)

  • 数据段(.bss和.data)

  • 代码段(.text)

其中栈空间是倒着向下增长的,堆区空间是向上增长的,栈和堆是相对增长,消耗中间的地址空间。mmap区和堆区也可以相对增长(64位中mmap区往哪边增长都可以)

内存映射

Linux 中通过将一块虚拟地址内存空间和一个文件对象关联起来,以初始化这块虚拟内存的内容,这个过程称为内存映射(memory mapping)。

这里的文件对象可以是:

  • ① Linux文件系统中的普通文件
  • ② 也可以是一个匿名文件,即一块全部包含二进制零的物理内存。

在这里插入图片描述

普通文件的内存映射:

  • 首先将用户程序的虚拟地址和磁盘文件进行映射,

  • 当访问虚拟页的时候,由缺页异常处理程序将磁盘文件内容加载到物理内存中,同时更新用户程序的虚拟页表中虚拟页号对应的物理页号,这样程序通过虚拟地址访问物理内存就相当于访问该文件内容,对物理内存操作就相当于操作该文件。

在这里插入图片描述

匿名文件的内存映射:

  • 直接将一块包含二进制零的物理内存和用户的虚拟地址进行映射,缺页异常处理程序将对应的物理页号更新到虚拟页表中即可。

需要注意,内存映射也是要经过页表将虚拟内存地址映射到物理内存地址的,并不是说可以直接在代码中访问到关联的物理内存地址。记住,用户程序中能访问到的永远是虚拟地址空间,即便是通过mmap内存映射也是如此。

共享内存映射

在这里插入图片描述

共享内存映射:

  • 当一个文件和程序 1 的虚拟地址建立内存映射之后,程序 2 需要访问该文件内容时,可以直接与对应的物理内存页建立映射,实现不同的程序的虚拟内存共享同一块物理内存,即共享同一个文件对象。

  • 共享内存映射的最佳应用就是著名的动态链接共享库(.so库文件),它可以节约物理内存避免重复浪费(相对于静态链接库而言)。通过共享内存映射,不同的应用程序只需要共享物理内存中的同一份共享库代码,不需要每个应用程序都保留一份,因此提高了内存利用率

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

然而,只要有一个程序试图写私有区域内的某个页面,那么这个写操作就会触发一个保护故障。故障处理程序注意到保护异常是由于程序试图写私有的写时赋值区域中的一个页面而引起的,它就会在物理内存中创建这个页面的一个新副本,更新页表项指向这个新的副本,然后恢复这个页面的可写权限。这就是写时复制技术。

内存映射函数 mmap

内存映射的详细流程图:https://www.processon.com/view/link/627f9bfdf346fb3cb3fb696f

#include <unistd.h>
#include <sys/mmam.h>
// 返回:若成功时则返回指向映射区域的指针,若出错则返回 MAP_FAILED(-1)
void *mmap(void *start, size_t length, int prot, int flags, int fd, off_t offset) 

在这里插入图片描述

参数 prot 包含描述新映射的虚拟内存区域的访问权限位:

  • PROT_EXEC:这个区域内的页面由可以被 CPU 执行的指令组成
  • PROT_READ:这个区域内的页面可读
  • PROT_WRITE:这个区域内的页面可写
  • PROT_NONE:这个区域内的页面不能被访问

参数 flags 由描述被映射对象类型的位组成:

  • MAP_ANON :如果设置了 MAP_ANON 标记位,那么这个被映射的对象就是一个匿名对象,而相应的虚拟页面是请求二进制零的
  • MAP_PRIVATE:表示被映射的对象是一个私有的、写时复制的对象
  • MAP_SHARED:表示是一个共享对象。
bufp = mmap(NULL, size, PROT_READ, MAP_PRIVATE | MAP_ANON, 0, 0) 

上面代码表示让内核新建一个新的包含size字节的只读、私有、请求二进制零虚拟内存区域。如果调用成功,那么bufp则是新区域的起始地址

#include <unistd.h>
#include <sys/mmam.h>
// 若成功则返回 0,若出错则返回 -1
int munmap(void *start, size_t length);

munmap 函数删除从虚拟地址 start 开始的,由接下来 length 字节组成的区域。接下来对已删除区域的引用会导致段错误。

在这里插入图片描述

  • Linux 提供了mmapmunmap函数来进行虚拟地址和文件对象的映射和删除映射操作
  • 操作系统加载应用的 ELF 文件时,用户程序的每一段虚拟地址都是通过mmap采用内存映射加载到内存的,就是把虚拟地址空间和 ELF 中某一部分关联映射,用户程序的某些段可能是私有的映射(如栈和运行时堆),某些可能是共享的映射(如so共享库映射区)

内存映射区的管理

用户程序的虚拟内存的每一段映射区,被抽象成一个结构体vm_area_struct,为提高查询效率,不同映射区之间的vm_area_struct使用链表+红黑树来维护。

在这里插入图片描述
在这里插入图片描述

问题:给你一个虚拟地址,如何快速找到这个虚拟地址位于哪一个 vm_area_struct ?

  • 顺序遍历链表,对于每个节点确定虚拟地址是否在节点映射虚拟地址范围内,时间复杂度 O(n)

  • mmap 是一个常见的操作,所以链表可能会挺长的

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

mmap流程:

在这里插入图片描述

内存布局总结图

32 位系统虚拟内存布局总结图链接:https://www.processon.com/view/link/6232f11d5653bb074b22d983

在这里插入图片描述

64 位系统虚拟内存布局总结图链接:https://www.processon.com/view/link/623311f8e401fd0726c20d50

在这里插入图片描述

64位直接映射区范围大小是64T,足够覆盖所有的物理内存范围,所以不需要也不存在高端内存映射区。

用户程序页表和内核页表

每个应用程序的虚拟地址空间分为两部分:

  • ① 用户态虚拟地址空间
  • ② 内核态虚拟地址空间
    在这里插入图片描述

所以一个应用程序的页表也有两部分:

  • ① 第一部分用于映射用户态虚拟页到物理页
  • ② 第二部分用于映射内核态虚拟页到物理页

其中:

  • 用户态虚拟页到物理页的映射,在 CPU 访问用户态虚拟内存发生缺页异常时,由缺页异常处理程序维护映射关系
  • 内核态虚拟页到物理页的映射,是在程序加载启动的时候,从内核页表拷贝过来的

注意:内核页表是所有应用程序共享的,而用户态页表是每个应用程序私有的,每个程序都不一样。

程序页表的每一个页表项中有一个标记位,来标记这个页表项是属于用户态还是内核态:

  • 当程序运行在用户态的时候,只能访问标记为用户态的页表项,
  • 当程序通过系统调用,陷入到内核态后,可以访问程序页表中的所有页表项
  • 内核程序是有特权的
  • 页表项:有效位、权限、物理页号
  • 标记位的作用:隔离内核态和用户态的页表

在这里插入图片描述

问题:为什么维护了内核页表,还要将内核页表拷贝到程序页表?

  • 主要为了提高性能,当一个应用程序通过系统调用陷入内核态时,就不需要切换页表了,直接使用程序页表就可以,因为程序页表中包含了内核页表部分。切换页表需要消耗性能,比如需要刷新 TLB 页表项缓存。

  • 空间换时间的设计

缺页异常处理程序

用户态缺页异常处理程序的执行逻辑流程图:https://www.processon.com/view/link/6235ab0ce0b34d75aad6ba71

问题:用户态程序访问页表会陷入内核态吗?

  • 首先,页表都是保存在内核态的,这个主要是为了安全,因为这样的话用户态程序就不能随意修改页表了,也就是只有内核可以修改页表。当发生缺页异常,执行内核中的缺页异常处理程序时,修改页表。

  • 程序处于用户态时,访问页表也不需要陷入内核态,因为访问页表是 MMU+TLB+CR3 这些硬件完成的不关程序啥事情,所以,这时程序也不需要陷入内核态。

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

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

相关文章

观测云产品更新 | 优化日志数据转发、索引绑定、基础设施自定义等

观测云更新 日志 数据转发&#xff1a;新增外部存储转发规则数据查询&#xff1b;支持启用/禁用转发规则&#xff1b;绑定索引&#xff1a;日志易新增标签绑定&#xff0c;从而实现更细颗粒度的数据范围查询授权能力。 基础设施 > 自定义 【默认属性】这一概念更改为【必…

绝佳盘点:2023年最好用的AI机器人

近几年人工智能可以说是以前所未有的速度在发展&#xff0c;越来越多的企业意识到&#xff0c;在运营的过程中学会熟练地应用AI机器人是可以帮助他们很好地提高工作效率的。那么有哪些AI机器人比较好用呢&#xff1f;接下来我会介绍几个个人觉得比较优秀的AI机器人工具&#xf…

【51单片机】6-点亮第一个LED灯

1.单片机编程的一般步骤 1.目标分析 点亮开发板上的LED灯 2.原理图【电路图】分析 1.目标器件&#xff08;LED&#xff09;工作原理 2.相关模块电路连接 3.控制线路分析&#xff1a;相关IO端口是哪些&#xff1f; 3.代码编写&#xff0c;编译 4.下载于调试 2.原理图与控制…

杂记 | 使用gitlab-runner将python项目以docker镜像方式流水线部署到服务器(解决部署缓慢和时区不对的问题)

文章目录 01 需求背景1.1 需求1.2 步骤 02 编写BaseDockerfile2.1 编写2.2 说明2.3 执行 03 编写Dockerfile04 编写.gitlab-ci.yml05 项目结构 01 需求背景 1.1 需求 我有一个python项目&#xff0c;该项目可能是一个服务器监控程序&#xff0c;也可能是一个后端程序&#xf…

【开关稳压器】LMR16030SDDA、LMR38010FDDAR,汽车类LMR43610MSC5RPERQ1低 EMI 同步降压稳压器

一、LMR16030SDDA 开关稳压器 IC REG BUCK ADJ 3A 8SOPWR LMR16030 是一款带有集成型高侧 MOSFET 的 60V、3A SIMPLE SWITCHER 降压稳压器。该器件具有4.3V 至 60V 的宽输入范围&#xff0c;适用于从工业到汽车各类应用中非稳压电源的电源调节。该稳压器在睡眠模式下的静态电流…

基于TensorFlow+CNN+协同过滤算法的智能电影推荐系统——深度学习算法应用(含微信小程序、ipynb工程源码)+MovieLens数据集(二)

目录 前言总体设计系统整体结构图系统流程图 运行环境模块实现1. 模型训练1&#xff09;数据集分析2&#xff09;数据预处理 相关其它博客工程源代码下载其它资料下载 前言 本项目专注于MovieLens数据集&#xff0c;并采用TensorFlow中的2D文本卷积网络模型。它结合了协同过滤…

h5下载文件,无兼容问题~

最近写了个页面&#xff0c;打开页面出现文件列表&#xff0c;用户可以下载文件。 失败方案 使用a标签进行下载&#xff0c;参考代码如下&#xff1a; 因为有批量下载的需求&#xff0c;这里将xhr请求单独封装到downloadFile.js中 // downloadFile.js const downloadFile …

Flutter超好用的路由库-fluro

文章目录 fluro的介绍fluro简介安装和导入路由配置导航到路由参数传递 fluro的典型使用创建路由管理类代码解释例子小结 初始化路由导航到路由 总结 fluro的介绍 fluro简介 fluro是一个流行的Flutter插件&#xff0c;用于实现高级路由管理。它提供了灵活的路由配置和导航功能…

VR科普研学基地科普开放日普乐蛙VR体验馆沉浸式体验设备

广州科普开放日来啦 2023年9月广州科普开放日来啦&#xff0c;9月16日周六上午9点&#xff0c;广州卓远非常荣幸地迎来了一批前来体验的家庭。 比原定的集合时间提前了近1个小时&#xff0c;已经开始有家长带着小朋友来到了VR科普基地&#xff0c;可见大家对VR科普体验的热情和…

轻量服务器是不是vps ?和vps有什么区别

​  轻量型服务器是介于云服务器和共享型服务器之间的一种解决方案。它提供较为独立的资源分配&#xff0c;但规模较小&#xff0c;适用于中小型网站和应用程序。轻量型服务器的硬件资源来源于大型的公有云集群的虚拟化技术。轻量型服务器的性能和带宽可能会稍逊于云服务器。…

【笨~~~】在python中导入另一个模块的函数时,为什么会运行模块中剩下的部分??顶层?

一个程序员一生中可能会邂逅各种各样的算法&#xff0c;但总有那么几种&#xff0c;是作为一个程序员一定会遇见且大概率需要掌握的算法。今天就来聊聊这些十分重要的“必抓&#xff01;”算法吧~ Python导入了其他文件中的函数&#xff0c;运行时连着这个文件一起运行了 在py…

椭圆曲线加密算法

椭圆曲线密码学&#xff08;Elliptic curve cryptography&#xff09;&#xff0c;简称ECC&#xff0c;是一种建立公开密钥加密的算法&#xff0c;也就是非对称加密。类似的还有RSA&#xff0c;ElGamal算法等。ECC被公认为在给定密钥长度下最安全的加密算法。比特币中的公私钥生…

什么是文档签名证书?PDF文档怎么签名?

什么是文档签名证书&#xff1f;在“互联网”时代&#xff0c;电子合同、电子证照、电子病历、电子保单等各类电子文档无纸化应用成为常态。如何让电子文档的签署、审批具有公信力及法律效力&#xff0c;防止伪造签名、假冒签名等问题出现&#xff0c;是电子文档无纸化应用的主…

画一个时钟(html+css+js)

这是一个很简约的时钟。。。。。。。 效果&#xff1a; 代码&#xff1a; <template><div class"demo-box"><div class"clock"><ul class"mark"><liv-for"(rotate, index) in rotatedAngles":key"i…

echarts图表 实现高度按照 内容撑起来或者超出部分滚动展示效果

背景&#xff1a;因为数据不固定 高度写死导致数据显示不全&#xff0c;所以图表高度要根据内容计算 实现代码如下&#xff1a; <divv-if"showCharts"id"business-bars"class"chart":style"{ height: chartHeight px }"></d…

如何做接口测试呢?接口测试有哪些工具

回想入职测试已经10年时间了&#xff0c;初入职场的我对于接口测试茫然不知。后来因为业务需要&#xff0c;开始慢慢接触接口测试。从最开始使用工具进行接口测试到编写代码实现接口自动化&#xff0c;到最后的测试平台开发。回想这一路走来感触颇深&#xff0c;因此为了避免打…

数据结构-----串(String)详解

目录 前言 1.串的定义 相关类型 2.串的储存结构 顺序储存表示 堆分配储存表示 块链储存表示 3.串的操作方式 4.串的匹配算法 &#xff08;1&#xff09;BF算法 过程原理 代码实现&#xff08;C/C&#xff09; 算法分析 &#xff08;2&#xff09;KMP算法 过程…

2.(vue3.x+vite)组件注册并调用

前端技术社区总目录(订阅之前请先查看该博客) 关联博客 1.(vue3.x+vite)封装组件 一:umd调用方式 1:引入umd.js <script src="./public/myvue5.umd.js"></script>2:编写代码调用 (1)umd方式,根据“5

四川天蝶电子商务有限公司真实吗?

四川天蝶电子商务有限公司是一家专注于电商行业的企业&#xff0c;他们通过自己的经验和专业知识&#xff0c;教人带货的方法和技巧。带货是指通过社交媒体或其他渠道&#xff0c;向消费者推销商品并实现销售的过程。 教人带货的方法主要有以下几点&#xff1a; 1.选择合适的平…

以酒为媒、以酒载道,五粮液携手首届“金熊猫奖”,讲好中国白酒故事

执笔 | 尼 奥 编辑 | 萧 萧 这是一次光影艺术与白酒酿造的和美之约&#xff0c;也是中国文化与世界多元文明的交融时刻&#xff0c;在影视与美酒的碰撞瞬间&#xff0c;共同擘画“美美与共&#xff0c;天下大同”的文明图景。 9月19-20日&#xff0c;以“多彩文明荣耀光影…