《深入理解计算机系统》(2):虚拟内存

news2024/9/28 23:26:13

虚拟内存是一种对主存的抽象概念。
(1)将主存看作一个存储在磁盘上的地址空间的高速缓存,在主存中只保存活动区域,并根据需要在磁盘和主存之间来回传送数据,通过这种方式高效地使用内存
(2)为每个进程提供一致的地址空间,从而简化内存管理。
(3)保护每个进程的地址空间不被其它进程破坏。
在这里插入图片描述

1、物理寻址
计算机系统的主存被组织成一个由M个连续的字节大小的单元组成的数组。每字节都有一个唯一的物理地址。第一个字节的地址为0,接下来的字节地址为1,再下一个为2,依此类推CPU访问内存的最自然的方式就是使用物理地址。这种方式称为物理寻址。
在这里插入图片描述

早期的PC使用物理寻址,而且诸如数字信号处理器、嵌人式微控制器以及Cray超级计算机这样的系统仍然继续使用这种寻址方式。然而,现代处理器使用的是一种称为虚拟寻址(virtual addressing)的寻址形式。

2、虚拟寻址
虚拟内存地址是指令用到的内存地址;物理内存地址是实际在内存硬件中的空间地址。
CPU通过生成一个虚拟地址来访问主存,这个虚拟地址在被送到内存之前先转换成适当的物理地址。将一个虚拟地址转换为物理地址的任务叫做地址翻译。就像异常处理一样,地址翻译需要CPU硬件和操作系统之间的紧密合作。CPU芯片上叫做内存管理单元(Memory Management Unit,MMU)的专用硬件,利用**存放在主存中的查询表(页表)**来动态翻译虚拟地址,该表的内容由操作系统管理。
在这里插入图片描述

3、虚拟页和物理页
虚拟内存被组织成一个由存放在磁盘上的N个连续的字节大小的单元组成的数组。每字节都有一个唯一的虚拟地址,作为数组索引。磁盘上数组的内容被缓存在主存中。
虚拟内存被分割为虚拟页VP,物理内存被分割为物理页PP。

在任意时刻,虚拟页面的集合都分为三个不相交的子集:

  • 未分配的:系统还未分配(或者创建)的页。未分配的块没有任何数据和它们相关联,因此也就不占用任何磁盘空间。
  • 已分配但缓存的:当前已缓存在物理内存中的已分配页,在主存中。
  • 已分配但未缓存的:未缓存在物理内存中的已分配页,在磁盘中。

4、页表
同任何缓存一样,虚拟内存系统必须有某种方法来判定一个虚拟页是否缓存在DRAM中的某个地方。如果是,系统还必须确定这个虚拟页存放在哪个物理页中。如果不命中,系统必须判断这个虚拟页存放在磁盘的哪个位置,在物理内存中选择一个牺牲页,并将虚拟页从磁盘复制到DRAM中,替换这个牺牲页。

这些功能是由软硬件联合提供的,包括操作系统软件、MMU(内存管理单元)中的地址翻译硬件和一个存放在物理内存中叫做页表(page table)的数据结构,页表将虚拟页映射到物理页。每次地址翻译硬件将一个虚拟地址转换为物理地址时,都会读取页表。操作系统负责维护页表的内容,以及在磁盘与DRAM之间来回传送页。

页表就是一个页表条目(Page Table Entry,PTE)的数组。虚拟地址空间中的每个页在页表中一个固定偏移量处都有一个PTE。
在这里插入图片描述
PTE中的有效位为0表示未分配,地址字段为null;或者已经分配了但是没有缓存到物理内存中,地址字段指向磁盘地址;为1时表示已经缓存到物理内存中,地址字段指向物理页号。

页命中:
CPU读取包含在虚拟内存中某虚拟页的一个字,该虚拟页已经缓存在主存中,使用PTE中的物理内存地址构造出这个字的物理地址。

缺页:
物理内存不命中即缺页。地址翻译硬件从内存中读取PTE,从有效位推断出该虚拟页未被缓存(未分配的PTE没有联系任何数据,不会被读取),并且触发一个缺页异常。缺页异常调用内核中的处理程序,该程序
(1)判断虚拟地址是否合法,是否是某个区域结构定义的区域,访问空白区域会触发段错误。
(2)内存访问是否合法,是否有读取该地址空间的权限。
(3)对合法的虚拟地址进行合法的操作:选择物理内存中的一个物理页作为牺牲页,从磁盘上用虚拟页的副本取代该牺牲页。程序返回之后CPU重新启动导致缺页的指令,正常读取不会产生异常。

页面分配:
调用malloc的结果,就是在磁盘上创建空间(创建新的虚拟页)并更新某个未分配的页表条目PTE,使它指向磁盘上这个新创建的页面。

5、内存映射
linux将一个虚拟内存区域和一个磁盘上的对象关联起来,初始化这个虚拟内存区域的内容,这个过程称为内存映射,映射为文件系统中的普通文件或者内核创建的匿名文件。
一个区域可以映射到一个普通磁盘文件的连续部分,例如一个可执行目标文件。文件区被分为页大小的片,每一片包含一个虚拟页面的初始内容。

共享对象和私有对象:
一个对象可以被映射到虚拟内存的一个区域,要么作为共享对象,要么作为私有对象。
共享对象:如果一个进程将一个共享对象映射到它的虚拟地址空间的一个区域内,那么这个进程对这个区域的任何写操作,对于那些也把这个共享对象映射到它们虚拟内存的其他进程而言,也是可见的。而且,这些变化也会反映在磁盘上的原始对象中。

私有对象:另一方面,对于一个映射到私有对象的区域做的改变,对于其他进程来说是不可见的,并且进程对这个区域所做的任何写操作都不会反映在磁盘上的对象中。

一个映射到共享对象的虚拟内存区域叫做共享区城。类似地,也有私有区城。

写时复制:
私有对象使用写时复制的技术映射到虚拟内存中。一个私有对象开始生命周期的方式和共享对象一样,在物理内存中只保存私有对象的一份副本。当一个进程试图写私有区域的某个界面,这个写操作会触发一个保护故障。处理程序会在物理内存中创建这个页面的一个新副本,并更新页表条目。程序返回时CPU重新执行写操作即正常执行。

fork函数:
用于创建一个进程,所创建的进程复制父进程的代码段/数据段/BSS段/堆/栈等所有用户空间信息;在内核中操作系统重新为其申请了一个PCB,并使用父进程的PCB进行初始化;

当fork函数被当前进程调用时,内核为新进程创建各种数据结构,并分配给它一个唯一的PID。为了给这个新进程创建虚拟内存,它创建了当前进程的mm_struct、区域结构和页表的原样副本。它将两个进程中的每个页面都标记为只读,并将两个进程中的每个区域结构都标记为私有的写时复制。

当 fork在新进程中返回时,新进程现在的虚拟内存刚好和调用fork时存在的虚拟内存相同。当这两个进程中的任一个后来进行写操作时,写时复制机制就会创建新页面,因此,也就为每个进程保持了私有地址空间的抽象概念。

execve函数:
在当前进程中加载并运行包含在可执行目标文件中的程序,用该程序替代当前程序。
(1)删除已存在的用户区域
(2)映射私有区域
(3)映射共享区域
(4)设置程序计数器

mmap函数:
要求内核创建一个新的虚拟内存区域,并将指定对象的一个连续的片映射到这个新的区域。munmap用来删除虚拟内存区域。

6、动态内存分配
运行时需要额外虚拟内存时,用动态内存分配器更加方便,移植性更好。动态内存分配器维护堆,将堆视为一组不同大小的块的集合来维护。每个块就是一个连续的虚拟内存片,要么是已分配的,要么是空闲的。

C标准库提供一个称为malloc程序包的显式分配器,程序通过调用malloc函数来从堆中分配块。
动态内存分配器,如malloc,可以通过使用mmap和munmap函数,显式地分配和释放堆内存。

内存碎片:
造成堆利用率很低的主要原因是一种称为碎片(fragmentation)的现象,当虽然有未使用的内存但不能用来满足分配请求时,就发生这种现象。有两种形式的碎片:内部碎片(internal fragmentation)和外部碎片(external fragmentation)。

内部碎片是在一个已分配块比有效载荷大时发生的。很多原因都可能造成这个问题。例如,一个分配器的实现可能对已分配块强加一个最小的大小值,而这个大小要比某个请求的有效载荷大。或者分配器可能增加块大小以满足对齐约束条件。

内部碎片的量化是简单明了的。它就是已分配块大小和它们的有效载荷大小之差的和。因此,在任意时刻,内部碎片的数量只取决于以前请求的模式和分配器的实现方式。

外部碎片是当空闲内存合计起来足够满足一个分配请求,但是没有一个单独的空闲块足够大可以来处理这个请求时发生的。那么如果不向内核请求额外的虚拟内存就无法满足这个请求,即使在堆中仍然有足够多空闲的字。问题的产生是由于这些空闲字是分在多个空闲块中的。

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

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

相关文章

30天入门Python(基础篇)——第4天:Python中的【输入】+【数据类型】的认识(万字建议点赞收藏)

文章目录 专栏导读上节课回顾Python中的输入Python中的数据类型1、可变数据类型2、不可变数据类型 如何查看一个变量(数据)的变量类型字符串(str不可变)整数(int不可变)浮点数(float不可变)列表&#xff08…

```,```中间添加 # + 空格 + 空行后遇到的底部空行出错,书接上回,处理空行

【python查找替换:查找空行,空行前后添加,中间添加 # 空格 空行后遇到的第1行文字? - CSDN App】http://t.csdnimg.cn/QiKCV def is_blank(line):return len(line.strip()) 0txt 时间戳: ("%Y-%m-%d %H:%M:…

软件设计师考试知识点大全思维导图

软件设计师考试知识点大全思维导图 欢迎交流学习

BDJ-A02-32、BRJ-A02-50比例减压阀放大板

BDJ-A02-210、BDJ-A02-100、BDJ-A02-32、BRJ-A02-50、BRJ-A02-100、BRJ-A02-210、BRJ-A02-315、BCJ-A03-315、BCJ-A06-100、BCJ-A08-50、BYJ-A02-20、BYJ-A02-40是比例减压阀,阀的二次压力与输入电信号成正比。此类阀工作时是通过电子放大器提供比例电磁铁的驱动电流…

技术干货:解密最受欢迎的开源 Serverless 框架弹性技术实现

作者:元毅 Knative 是一款基于 Kubernetes 的开源 Serverless 应用编排框架,其目标是制定云原生、跨平台的 Serverless 应用编排标准。Knative 主要功能包括基于请求的自动弹性、缩容到 0、多版本管理、基于流量的灰度发布以及事件驱动等。 弹性是 Ser…

kali linux安装redis

官网:Install Redis from Source | Redis wget https://download.redis.io/redis-stable.tar.gztar -xzvf redis-stable.tar.gz cd redis-stable make显示如下即可进入下一步 sudo make installredis-server 可以看到已经可以使用了。 但是由于第一次使用导致了re…

微信支付v2

文档: https://pay.weixin.qq.com/wiki/doc/api/index.html 微信小程序:https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter11_1 需要一个微信认证后的小程序,,还需要一个,在微信商户平台,&…

matlab实现对极地投影数据的投影转换

图片摘要 前段时间,我写了一个专栏《联合matlab和Arcgis进行netcdf格式的雪覆盖数据的重新投影栅格》,介绍了如何利用Arcgis实现极地投影的转换。今天,我提供一个matlab重采样的方法实现投影转换。 我们这次使用的数据是北冰洋逐日的海平面高…

【每日一题】1094. 拼车

1094. 拼车 - 力扣(LeetCode) 车上最初有 capacity 个空座位。车 只能 向一个方向行驶(也就是说,不允许掉头或改变方向) 给定整数 capacity 和一个数组 trips , trip[i] [numPassengersi, fromi, toi] 表示第 i 次旅…

相机坐标系之间的转换

一、坐标系之间的转换 一个有4个坐标系:图像坐标系、像素坐标系、相机坐标系、世界坐标系。 1.图像坐标系和像素坐标系之间的转换 图像坐标系和像素坐标系在同一个平面,利用平面坐标系之间的转换关系可以之知道两个坐标系变换的公式,并且该…

Log4j2的JNDI注入漏洞(CVE-2021-44228)原理分析与思考

目录 前言 一、 前置知识 1.1 Log4j2 1.2 Log4j2 Lookup 1.3 JNDI 1.4 JNDI注入 二、 漏洞复现 三、 漏洞原理 3.1 MessagePatternConverter.format() 3.2 StrSubstitutor.resolveVariable() 3.3 Interpolator.lookup() 3.4 JndiLookup.lookup() 3.5 JndiManager.l…

cos文件上传demo (精简版通用)

1. 依赖 <!--腾讯云cos依赖--> <dependency><groupId>com.qcloud</groupId><artifactId>cos_api</artifactId><version>5.6.54</version> </dependency> 2. FileController import com.ruoyi.common.core.domain.AjaxRe…

网络层协议—IP协议

网络层协议—IP协议 文章目录 网络层协议—IP协议网络层简介IP协议简介IP协议文格式IP协议报头实现网络互联的使用设备 网段划分IP地址划分子网掩码IP地址的特点特殊的IP地址IP地址的数量限制私有IP地址和公网IP地址NAT技术 路由报文的分片与组装IP地址和硬件地址 网络层简介 …

2023.10.8 基本 Thread 线程详解

目录 Thread 常见构造方法 Thread 常见属性 创建一个 Thread 线程 使用 jconsole 命令观察线程 中断一个 Thread 线程 等待一个 Thread 线程 休眠当前 Thread 线程 让出当前 Thread 线程的 CPU 资源 线程的状态 Thread 常见构造方法 方法说明Thread()创建线程对…

Nginx 重新编译添加新的模块

编译安装Nginx的时候&#xff0c;有些模块默认并不会安装&#xff0c;比如http_ssl_module&#xff0c;那么为了让Nginx支持HTTPS&#xff0c;必须添加这个模块。 下面讲解如何在已经安装过后再次添加新的模块。 1、找到安装nginx的源码根目录(即安装包存放目录)&#xff0c;…

2023年【G1工业锅炉司炉】考试题及G1工业锅炉司炉模拟考试

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 2023年G1工业锅炉司炉考试题为正在备考G1工业锅炉司炉操作证的学员准备的理论考试专题&#xff0c;每个月更新的G1工业锅炉司炉模拟考试祝您顺利通过G1工业锅炉司炉考试。 1、【多选题】TSGG0001-2012《锅炉安全技术监…

Potplayer结合cpolar内网穿透实现公网访问群晖WebDAV

把potplayer变成netflix需要几步&#xff1f; ​ 国内流媒体平台的内容让人一言难尽&#xff0c;就算是购买了国外的优秀作品&#xff0c;也总是在关键剧情上删删减减&#xff0c;就算是充了会员&#xff0c;效果如何&#xff1f; 广大网友不得不选择自己找资源下到本地&#x…

剪切板中,经常用到的gpt编程提问

/data/user/0/org.qpython.qpy/files/bin/qpy thon3.sh "/storage/emulated/0/qpython/评论 截图问题1.矩阵2.1.2.1空行问题1.4.5.py" && exit .1.2.1空行问题1.4.5.py" && exit < 时间戳&#xff1a; 时间戳&#xff1a; ("…

springboot 捕获特点异常信息并处理

前端获取效果图 springboot 捕获特点异常信息并处理 import com.one.utils.JSONResult; //JSONResult定义处理结果对象 import org.springframework.web.bind.annotation.ExceptionHandler

Flink开发环境搭建与提交运行Flink应用程序

Flink开发环境搭建与提交运行Flink应用程序 Flink概述环境 Flink程序开发项目构建添加依赖安装Netcat实现经典的词频统计批处理示例流处理示例 Flink Web UI 命令行提交作业编写Flink程序打包上传Jar提交作业查看任务测试 Web UI提交作业提交作业测试 Flink 概述 Apache Flink…