一文彻底搞懂操作系统“内存管理“【地址空间+重定位+虚拟内存+分页】

想要更好的了解操作系统的"内存管理",心中要带着疑问去寻找答案;这样才能有一种探索未知的兴趣,而不至于迷失在枯燥的时间里。

🎈如今的计算机基本都支持运行比内存大的进程,众所周知,程序运行需要先装载到内存,它都装不下,那么它是怎么运行的呢?

🎈当你追寻各种流行的软件时,是否想过计算机在背后做了多少能努力?我运行一个程序,它怎么给我做到内存分配的呢?怎么做到各个软件之间的互不干扰呢?


1.初识物理内存

物理内存就是0~某个上限的地址集合
在这里插入图片描述

早期的存储器没有抽象,那么程序必须直接访问物理内存。如下面这条指令

	MOV REGISTERR1 2000

🔔将位置为2000的物理内存的内容移到REGISTERR1中,但是这种情况只能有一个程序在运行;如果第一个程序在某个位置存储值之后,第二个程序又在该位置写入了一个新值,将擦除第一个程序写入的值,这两个程序就会直接崩溃。

❓ 如果直接使用物理内存,能不能运行程序呢?
在这里插入图片描述
当然可以,每次只能运行一个程序,当一个程序运行结束后,就把新的程序装入内存,覆盖前一个程序。

在这里插入图片描述

❓ 如果直接使用物理内存,能不能运行多个程序呢?

📚 这个是可行的,IBM的360早期模型有这种实现,它将内存划分为许许多多的块(每个块都是0~某个地址),为每个块分配一个4位的保护键。每个进程只能访问自身PSW(存有4位码)与保护键相同的内存,

这种虽然能够解决用户程序之间的相互干扰,但也有一个很大的缺陷:a程序运行之后,运行b程序,JMP20跳转到20的位置去执行了ADD指令,本来应该跳转到16400位置去执行SUB指令的。所以需要引入重定位技术

在这里插入图片描述
一句话总结:“如果要做到多个程序在内存中互不影响,需要解决两个问题:保护和重定位”。


2.存储器抽象——地址空间

🙄对于前面提到两个问题:" 保 护 和 重 定 位 保护和重定位 ,前者大佬们提出了一个方案,即地址空间。

地址空间:进程用于寻址的地址集合。每个进程都有自己独立的地址空间。

❓有了地址空间,怎么解决一个进程的地址28对应的物理地址与另外一个进程地址28所对应的物理地址不同呢?一个比较简单的方法使用动态重定位。

2.1.动态重定位(基址寄存器+界限寄存器):

它将每个进程的地址空间映射到不同的物理内存,通常是在CPU内置两个寄存器:基址寄存器和界限寄存器,每一个进程访问内存取一条指令进行读或写数据,CPU在将虚拟地址发送到内存总线前,会自动加上基址寄存器的值。看下图:
在这里插入图片描述

如果,执行虚拟地址位20的指令,首先CPU会加上基址寄存器的值 (20+10240=10260),如果访问地址超过了界限,产生错误并终止访问。

❗采用这种基址寄存器+界限寄存器这种方式的缺点就是每次访问内存前都要进行加法运算。

在这里插入图片描述
那么内存超载之后,怎么解决的呢?最通用的两种方法是交换技术虚拟内存

2.2.1交换技术

🎈顾名思义"交换技术"就是将内存中的数据保存到磁盘中,使用时再拿进来。

在这里插入图片描述
最开始只有进程A,之后进程B和进程C被加载到内存,当进程D被调用时,进程A别交换到磁盘。如果后面A进程再被调到内存时,它的地址就会发生变化,所以需要通过硬件对其地址进行重定位。 例如:前面提到的基址寄存器和界限寄存器就适用于这种交换技术。

🔔在交换过程产生了许多小的空闲区,通过将所有进程尽可能地向下移动,能够将这些小的空闲区合成一大块。该技术被称为”内存紧缩 ",通常不进行这个操作,因为它要花费大量CPU时间。

❓另外设想一下,如果某个进程内存不足,它就崩了吗?
在这里插入图片描述
大多数设计语言在堆中动态分配内存,当进程空间增长时就会产生问题,为例解决内存区域不足地问题,预留了一段空闲区供堆栈(向下)和数据段(向上)扩张。
在这里插入图片描述

❓操作系统如何做到对动态分配内存进行管理的呢?在这里插入图片描述

2.2.2.空闲区内存管理

在动态分配内存时,操作系统必须进行管理,有两种跟踪内存的使用状况:位图和空闲区链表

📜 (1)位图
在这里插入图片描述

✨分配单元的大小和内存的大小决定了位图的大小。

📜 (2)链表

对应上面的位图
在这里插入图片描述

为了更方便的回收内存,使用双链表将更为优秀。例如当某个进程结束,回收内存时,我们可以考虑如果该节点的pre指针指向的前一个块是否为空,如果是直接合并成一个新的块即可;next指向的也同样如此。

❓基于此链表的管理,那么为进程分配内存时,是分配大内存还是同样大的内存,如何做到效率最高?

(1)首次适配算法:沿着链表头部进行搜索,直到找到一个足够大的空闲区;将其分为两部分,一部分供进程使用,另外一部分是多余出来的内存形成一个新的空闲区。

(2)下次适配算法 :首次适配算法稍微修改就可以得到下次适配算法,首次适配算法每次都从头开始搜索,而下次适配算法,从上次搜索结束的位置作为起始位置。

(3)最佳适配算法 :搜索整个链表,找到最接近实际需要的空闲区进行分配;该算法能够避免拆分一个以后可能用到的空闲区。最佳适配算法会产生很多小的空闲区,可以使用最坏适配算法”,即每次都分配最大的空闲区。据说这不是个好主意。

在这里插入图片描述
此外科学家们还提出了很多优秀的注意…

👨🏽‍🔧说:我可以为进程和空闲区维护各自独立的链表,那么前面的四个算法速度都能得到提高
🎅🏽说:速度是能提高,但是内存释放时速度较慢;需要将回收的内存从进程链表中删除,然后插入到空闲区链表。
👨🏽‍🔧说:我还可以进行优化,可以不使用单独的数据结构存放空闲区链表,将这些信息保存在空闲区;每个空闲区的第一个字表示空闲区大小,第二个字指向下一个空闲区;比起使用空闲区链表少了一个字。

(4)快速适配算法 :有一个N项表,第一项指向4KB的空闲区链表头,第二项指向8KB的空闲区链表头…


❓当你的某个程序大到整个内存都无法存储下时,你怎么办?如果解决?

科学家们首先提出的是将这个程序分成多个段 , 将程序分段执行,将要运行的段可以将已经运行完段的内存内存进行覆盖; 这种方式虽然可行,但是非常复杂,据说很少程序员能够掌握!

在这里插入图片描述

2.3.虚拟内存

🎈虚拟内存的核心思想 : 每个进程都有自己独立的地址空间, 这个空间被分为多个块, 每一块称为页或者页面。这些页都有连续的地址范围,被映射到物理内存;并不是所有的页都在内存中才能运行程序;当程序运行时,如果发现缺少了某个页,操作系统会将其缺失的部分装入内存重新执行失败的指令。

2.3.1.分页(下面默认计算机都使用了虚拟内存技术)

大部分的虚拟内存都使用了一种称为分页的技术,看下面这条指令

	MOV REG,1000  //将地址为1000的内存单元复制到REG中

由程序产生的地址称为虚拟地址,它们构成了一个虚拟地址空间;当计算机使用了虚拟内存之后,并不会将该虚拟地址直接送到内存总线上,而是被送到CPU中的MMU(内存管理单元),MMU将虚拟地址映射为物理内存地址。(下图虚拟地址每一块称为一页,物理内存每一块称为页框。上面虚拟内存提到的)

在这里插入图片描述

例如以下指令,它对应的物理地址为4096

MOV REG, 8192

上图中有的页面并没有被映射,当执行指令在没有映射的页面时,CPU就会发生缺页中断;操作系统之后会将一个很少使用的页框把它写入磁盘,将需要访问的页面读到刚才回收的页框中,修改映射关系,重新执行引起缺页中断的指令。

这特别像一个函数,参数是虚拟地址,返回的是物理地址。

它具体怎么实现的呢?

  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
大数据和算法、数据分析的应用场景非常广泛,可以涵盖各个行业和领域。以下是一些常见的大数据和算法、数据分析应用场景: 电子商务:通过收集用户消费习惯、季节和产品生命周期的数据,建立算法模型来确定下一个月、几个月甚至一年的消费者需求。这样可以提高订单转化率。在营销方面,可以给买家贴标签,建立人群画像,针对不同人群精准投放广告和优惠券。 医疗保健:医生根据患者的症状和检查结果,结合自身经验得出结论,最终提供相应的治疗方案。不同地区的医疗水平各不相同,尤其是高水平医生短缺,好医院分布不均。根据患者的症状检测报告,通过病理分析模型确定病因,并提供具体的治疗方案。即使在医疗保健不发达的地区,也只需要输入患者的症状和医疗记录,就可以体验高级医生的服务。 金融风险管理:金融机构利用大数据技术来分析交易数据、市场趋势和经济指标,识别潜在的风险和欺诈行为。大数据技术还可以用于建立预测模型,帮助金融机构预测市场变化,制定有效的风险管理策略。 物流和供应链管理:大数据技术可以优化物流运输路线、库存管理和供应链协调。通过分析大量的实时物流数据和市场需求数据,企业可以提高配送效率,减少成本,并提供更好的客户服务。 智能城市和交通管理:大数据技术可以帮助城市管理者监测和分析交通流量、能源消耗和环境污染等数据,为城市规划和交通管理提供决策支持。通过智能化的交通系统和城市基础设施,可以提高交通效率
Python面向对象编程(Object-Oriented Programming,简称OOP)是一种编程范式,它将数据和操作封装在对象中,通过对象之间的交互实现程序的设计和开发。下面是一些关键概念,帮助你更好地理解Python面向对象编程。 1. 类(Class):类是对象的蓝图或模板,描述了对象的属性和行为。它定义了对象的特征和方法。例如,我们可以定义一个名为"Car"的类来表示汽车,其中包含属性(如颜色、型号)和方法(如加速、刹车)。 2. 对象(Object):对象是类的实例,是具体的实体。通过实例化类,我们可以创建一个对象。例如,我们可以创建一个名为"my_car"的对象,它是基于"Car"类的实例。 3. 属性(Attribute):属性是对象的特征,用于描述对象的状态。每个对象都可以具有一组属性。例如,"Car"类的属性可以包括颜色、型号等。 4. 方法(Method):方法是对象的行为,用于定义对象的操作。每个对象都可以具有一组方法。例如,"Car"类的方法可以包括加速、刹车等。 5. 继承(Inheritance):继承是一种机制,允许我们创建一个新类(称为子类),从现有类(称为父类)继承属性和方法。子类可以扩展或修改父类的功能。继承可以实现代码用和层次化设计。 6. 多态(Polymorphism):多态是一种特性,允许不同类的对象对同一方法做出不同的响应。多态提高了代码的灵活性和可扩展性。 7. 封装(Encapsulation):封装是一种将数据和操作封装在对象中的机制,隐藏了对象的内部实现细节,只暴露必要的接口给外部使用。这样可以保护数据的安全性,提供了更好的模块化和代码复用性。 通过理解这些概念,你可以更好地掌握Python面向对象编程。在实践中,你可以使用类来创建对象,操作对象的属性和调用对象的方法,通过继承和多态实现代码的灵活性和可扩展性,通过封装保护数据的安全性和提高代码的可维护性。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Thecoastlines

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值