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

虚拟内存布局

在这里插入图片描述

虚拟地址空间大小:

  • 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.xdnf.cn/news/141751.html

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

相关文章

更新andriod studio版本,项目编译报could not find org.junit.jupiter:junit-jupiter

原本使用Android Studio 版本是4.1.1&#xff0c;现更新为 点击build -》 build bundle -》build apk&#xff0c;项目报 Could not determine the dependencies of task :app:compileDebugUnitTestJavaWithJavac. > Could not resolve all task dependencies for configur…

HTML那些重要的知识点

文章目录 ⭐️写在前面的话⭐️一、HTML1.1 锚点链接跳转到当前页面的指定位置跳转到其他页面的指定位置 1.2 自定义列表1.3 表格的跨行跨列1.4 视频和音频内容1.5 页面结构规范1.6 ifram内联框架1.7 表单1.7.1 form标签1.7.2 原生表单部件1.7.3 下拉框1.7.4 文本域1.7.5 文件域…

基于微信小程序的健康评估系统设计与实现(源码+lw+部署文档+讲解等)

文章目录 前言运行环境说明用户微信端的主要功能有&#xff1a;医生微信端的主要功能有&#xff1a;管理员的主要功能有&#xff1a;具体实现截图详细视频演示为什么选择我自己的网站自己的小程序&#xff08;小蔡coding&#xff09;有保障的售后福利 代码参考论文参考源码获取…

【每日一题】658. 找到 K 个最接近的元素

658. 找到 K 个最接近的元素 - 力扣&#xff08;LeetCode&#xff09; 给定一个 排序好 的数组 arr &#xff0c;两个整数 k 和 x &#xff0c;从数组中找到最靠近 x&#xff08;两数之差最小&#xff09;的 k 个数。返回的结果必须要是按升序排好的。 整数 a 比整数 b 更接近 …

【PDF】pdf 学习之路

PDF 文件格式解析 https://www.cnblogs.com/theyangfan/p/17074647.html 权威的文档&#xff1a; 推荐第一个连接&#xff1a; PDF Explained &#xff08;译作《PDF 解析》&#xff09; | PDF-Explained《PDF 解析》https://zxyle.github.io/PDF-Explained/ https://zxyle…

怎样的外发文件管理办法 能够避免数据外发泄露?

在日常办公中&#xff0c;重要文件保密管理可谓“老生常谈”。但我们往往容易忽视&#xff0c;文件保密管理并非个体所能独立完成&#xff0c;在整个文件运转过程中&#xff0c;存在多名经手人&#xff0c;一人发生疏忽&#xff0c;则整个安全屏障都会被打破。 因此&#xff0c…

Jetpack Compose中的Navigation从入门到精通完全指南

Jetpack Compose中的Navigation从入门到精通完全指南 什么是Android导航 导航帮助您理解应用程序在不同组件间的移动方式。 Android JetPack Navigation可以帮助您以简单的方式实现高级导航。 导航组件由三个主要部分组成&#xff1a; 导航图(Navigation Graph)&#xff1…

前端关于对象中套用对象传参的小问题

在js的对象是引用类型的&#xff0c;他如果里面还套用对象的话那么通过axios传参给后端就会出现一个问题&#xff0c;就是【object&#xff0c;object】这种包装形式 那么如何来解决这个问题呢&#xff1f; 其实这就是要对数据传输中json格式要有一定的了解才可以解决这个问题…

【李沐深度学习笔记】线性代数

课程地址和说明 线性代数p1 本系列文章是我学习李沐老师深度学习系列课程的学习笔记&#xff0c;可能会对李沐老师上课没讲到的进行补充。 线性代数 标量 标量&#xff08;scalar&#xff09;&#xff0c;亦称“无向量”。有些物理量&#xff0c;只具有数值大小&#xff0c…

低功耗无线扫描唤醒技术,重塑物联网蓝牙新体验

随着人类社会活动的信息化和通信技术的发展&#xff0c;传统设施越来越倾向于网络化、无线化。物联网被人们视为继计算机、互联网之后信息技术产业发展的第三次革命。无线短距离通信方式是物联网的主要通信方式之一&#xff0c;随着物联网终端通信设备应用越来越广&#xff0c;…

AIGC专栏7——EasyPhoto 人像训练与生成原理详解

AIGC专栏7——EasyPhoto 人像训练与生成原理详解 学习前言源码下载地址为什么是LoraEasyPhoto的训练流程1、数据的预处理a、人像排序i、人脸特征向量提取过程ii、人脸偏移角度计算iii、人像排序 b、人像分割与修复i、人像分割ii、图像修复与超分处理 2、Lora模型训练a、训练的基…

Python爬虫自动切换爬虫ip的完美方案

在进行网络爬虫时&#xff0c;经常会遇到需要切换爬虫ip的情况&#xff0c;以绕过限制或保护自己的爬虫请求。今天&#xff0c;我将为你介绍Python爬虫中自动切换爬虫ip的终极方案&#xff0c;让你的爬虫更加高效稳定。 步骤一&#xff1a;准备爬虫ip池 首先&#xff0c;你需要…

二值贝叶斯滤波计算4d毫米波聚类目标动静属性

机器人学中有些问题是二值问题&#xff0c;对于这种二值问题的概率评估问题可以用二值贝叶斯滤波器binary Bayes filter来解决的。比如机器人前方有一个门&#xff0c;机器人想判断这个门是开是关。这个二值状态是固定的&#xff0c;并不会随着测量数据变量的改变而改变。就像门…

mysql用事务实现更新数据

前言&#xff1a;在手动批量更新正式环境数据库时&#xff0c;建议使用事物进行更新&#xff0c;避免更错数据&#xff0c;造成不必要的麻烦。 现表中有三条数据&#xff0c;使用事物批量将name字段为mgx&#xff0c;phone字段为17837107346&#xff0c;所有数据中的address字段…

解决Vue设置图片的动态src不生效的问题

一、问题描述 在vue项目中&#xff0c;想要动态设置img的src时&#xff0c;此时发现图片会加载失败。在Vue代码中是这样写的&#xff1a; 在Vue的data中是这样写的&#xff1a; 我的图片在根目录下的static里面&#xff1a; 但是在页面上这个图片却无法加载出来。 二、解决方案…

抖音SEO矩阵系统源码开发搭建

1. 确定需求和功能&#xff1a;明确系统的主要目标和需要实现的功能&#xff0c;包括关键词研究、短视频制作、外链建设、数据分析、账号设置优化等方面。 2. 设计系统架构&#xff1a;根据需求和功能确定系统的架构&#xff0c;包括前端、后端、数据库等部分的设计&#xff0…

惠普P1108激光打印机报错光束探测错误检修

在使用打印机的过程中&#xff0c;有时候会遇到光束探测错误的问题&#xff0c;导致打印机无法正常工作。这个问题可能是由多种原因引起的&#xff0c;包括硬件故障、驱动程序错误、操作系统问题等。在这里&#xff0c;我将为您提供一些解决光束探测错误的方法。 故障描述&…

Spring Boot:控制器调用模板引擎渲染数据的基本过程

目录 基础知识注解&#xff1a; Controller方法&#xff1a;RequestMapping 基本过程添加 FreeMarker 依赖创建控制器方法创建 FTL 文件 基础知识 注解&#xff1a; Controller 控制器注解&#xff0c;表示这个类是一个控制器类&#xff0c;里面定义了一些处理客户端请求的方…

Springcloud实战之自研分布式id生成器

一&#xff0c;背景 日常开发中&#xff0c;我们需要对系统中的各种数据使用 ID 唯一表示&#xff0c;比如用户 ID 对应且仅对应一个人&#xff0c;商品 ID 对应且仅对应一件商品&#xff0c;订单 ID 对应且仅对应 一个订单。我们现实生活中也有各种 ID &#xff0c;比如身…

TCP 和 UDP哪个更好

传输控制协议 &#xff08;TCP&#xff09; 和用户数据报协议 &#xff08;UDP&#xff09; 是互联网的基础支柱&#xff0c;支持从网络源到目的地的不同类型的数据传输。TCP更可靠&#xff0c;而UDP优先考虑速度和效率。本文解释了两种协议的工作原理&#xff0c;并详细讨论了…