热门标签 | HotTags
当前位置:  开发笔记 > 后端 > 正文

OS学习笔记:内存管理

四、内存管理1.内存管理的基本概念操作系统对内存的划分和动态分配程序的编译由编译程序将用户源代码编译成cpu可执行的目标代码(.o文件)ÿ

四、内存管理


1.内存管理的基本概念

操作系统对内存的划分和动态分配

img

程序的编译

由编译程序将用户源代码编译成cpu可执行的目标代码(.o文件),产生了若干个目标模块(即若干程序段)。


程序的链接

根据外部访问符号名表(如变量名、函数名等),将经过编译或汇编 得到的一组目标模块以及它们所需要的库函数,装配成一个完整的装入模块


静态链接

下图B和C都属于外部调用符号,在将这几个目标模块装配成一个装入模块时,须解决以下两个问题:

(1) 对相对地址进行修改。

(2) 变换外部调用符号。

img

这种先进行链接所形成的一个完整的装入模块,又称为可执行文件。通常都不再拆开它,要运行时可直接将它装入内存。这种事先进行链接,以后不再拆开的链接方式,称为静态链接方式。


装入时动态链接(所有的模块都装入内存)

用户源程序经编译后所得的目标模块,是在装入内存时边装入边链接的, 然后再按照上图所示的方式来修改目标模块中的相对地址。

优点:


  1. 便于修改和更新。对于经静态链接装配在一起的装入模块,如果要修改或更新其中的某个目标模块,则要求重新打开装入模块。这不仅是低效的,而且有时是不可能的。若采用动态链接方式,由于各目标模块是分开存放的,所以要修改或更新各目标模块是件非常容易的事。
  2. 便于实现对目标模块的共享。在采用静态链接方式时,每个应用模块都必须含有其目标模块的拷贝,无法实现对目标模块的共享。但采用装入时动态链接方式,OS则很容易将一个目标模块链接到几个应用模块上,实现多个应用程序对该模块的共享。

运行时动态链接(需要某个模块时才装入内存)

在许多情况下,应用程序在运行时,每次要运行的模块可能是不相同的。但由于事先无法知道本次要运行哪些模块,故只能是将所有可能要运行到的模块都全部装入内存,并在装入时全部链接在一起。显然这是低效的,因为往往会有些目标模块根本就不运行。比较典型的例子是作为错误处理用的目标模块,如果程序在整个运行过程中都不出现错误,则显然就不会用到该模块。


在执行过程中,当发现一个被调用模块尚未装入内存时,立即由OS去找到该模块并将之装入内存,把它链接到调用者模块上。凡在执行过程中未被用到的目标模块,都不会被调入内存和被链接到装入模块上,这样不仅可加快程序的装入过程,而且可节省大量的内存空间。

####程序的装入

由装入程序将装入模块装入内存,构造PCB,形成进程,开始运行(使用物理地址)。


绝对装入方式

在编译时,如果知道程序将驻留在内存的什么位置,那么,编译程序将产生绝对地址的目标代码。 绝对装入程序按照装入模块中的地址,将程序和数据装入内存。 装入模块被装入内存后,由于程序中的逻辑地址与实际内存地址完全相同,故不须对程序和数据的地址进行修改。程序中所使用的绝对地址,既可在编译或汇编时给出,也可由程序员直接赋予。

注:
由于内存划分为系统区和用户区,程序实际在用户区执行,故实际上程序的实际内存地址也有一定的增加,不可能像逻辑地址一样从0开始。


  • 优点:使CPU执行目标代码快
  • 缺点:
    1. 由于内存大小限制,能装入内存并发执行的进程数大大减少
    2. 编译程序必须知道内存的当前空闲地址部分和其地址,并且把进程的不同程序段连续地存放起来,编译非常复杂。

静态地址重定位

绝对装入方式只能将目标模块装入到内存中事先指定的位置。在多道程序环境下,编译程序不可能预知所编译的目标模块应放在内存的何处,因此,绝对装入方式只适用于单道程序环境

在多道程序环境下,所得到的目标模块的起始地址通常是从 0 开始的,程序中的其它地址也都是相对于起始地址计算的。此时应采用可重定位装入方式,根据内存的当前情况,将装入模块装入到内存的适当位置。


静态地址重定位:即在程序装入对目标代码装入内存的过程中完成,是指在程序开始运行前,程序中指令和数据的各个地址均已完成重定位,即完成虚拟地址到内存地址映射。地址变换通常是在装入时一次完成的,以后不再改变

img


  • 优点:无需硬件支持
  • 缺点:
    1. 程序重定位之后就不能在内存中搬动了;
    2. 要求程序的存储空间是连续的,不能把程序放在若干个不连续的区域中。

动态地址重定位

可重定位装入方式可将装入模块装入到内存中任何允许的位置,故可用于多道程序环境;但这种方式并不允许程序运行时在内存中移动位置。因为,程序在内存中的移动,意味着它的物理位置发生了变化, 这时必须对程序和数据的地址(是绝对地址)进行修改后方能运行。然而,实际情况是,在运行过程中它在内存中的位置可能经常要改变,此时就应采用动态运行时装入的方式。


动态地址重定位:不是在程序执行之前而是在程序执行过程中进行地址变换。更确切的说,是把这种地址转换推迟到程序真正要执行时才进行,即在每次访问内存单元前才将要访问的程序或数据地址变换成内存地址。动态重定位可使装入模块不加任何修改而装入内存。为使地址转换不影响指令的执行速度,这种方式需要一个重定位寄存器的支持。

img

优点:


  1. 目标模块装入内存时无需任何修改,因而装入之后再搬迁也不会影响其正确执行,这对于存储器紧缩、解决碎片问题是极其有利的;
  2. 一个程序由若干个相对独立的目标模块组成时,每个目标模块各装入一个存储区域,这些存储区域可以不是顺序相邻的,只要各个模块有自己对应的定位寄存器就行。

缺点:需要硬件支持。


逻辑地址和物理地址空间

程序经过编译后,每个目标模块都是从0号单元开始编址,称为该目标模块的相对地址(或逻辑地址)。

物理地址空间是指内存中物理单元的集合,它是地址转换的最终地址,进程在运行时执行指令和访问数据都要通过物理地址从主存中存取。当装入程序(Loader)将可执行代码装入内存时,必须通过地址转换将逻辑地址转换成物理地址,这个过程称为地址重定位


对换与覆盖

覆盖与对换技术是在多道程序环境下用来扩充内存的两种方法。

覆盖与对换可以解决在小的内存空间运行大作业的问题,是“扩充”内存容量和提高内存利用率的有效措施。

覆盖技术主要用在早期的 OS 中,对换技术则用在现代OS 中。


对换

摘自:操作系统存储器管理之覆盖与对换

所谓“对换” ,是指将暂时不用的某个进程及数据(首先是处于阻塞状态优先级最低的)部分(或全部)从内存移到到外存(备份区或对换区)中去,让出内存空间,同时将某个需要的进程调入到内存中,让其运行。

交换技术也是“扩充”内存容量和提高内存利用率的有效措施。

交换到外存的进程需要时可以被再次交换回(选择换出时间最久的)内存中继续执行。

图示

对换的类型


  • 整体对换:进程对换,解决内存紧张问题。 (中级调度)
  • 部分对换:页面对换/分段对换,提供虚存支持。

对换空间的管理


  • 具有对换功能的 OS 中,通常把外存分为文件区和对换区。前者用于存放文件,后者存放从内存换出的进程。对换区比文件区侧重于对换速度。因此对换区一般采用连续分配。

进程的换出与换入


  • 选择换出进程:优先级,进程状态。
  • 选择换入进程:优先级,进程状态,换出时间等。

重定位


2.连续内存分配方法

连续分配:程序中代码或数据的逻辑地址相邻,体现在内存空间分配时物理地址的相邻


2.1单一连续分配


  • 简单,无外部碎片
  • 只能用于单用户、单任务的操作系统,有内部碎片

2.2固定连续分配


  • 无外部碎片
  • 有内部碎片,存储空间利用率低

2.3动态分区分配


  • 无内部碎片,有外部碎片
  • 动态分区的分配策略(★★★★★)
  • 首次适应(★★★★):按地址从小到大依次寻找空闲分区,将第一个能满足要求的空闲分区分配给程序
  • 最佳适应:按容量从小到大依次寻找空闲分区,将第一个能满足要求的空闲分区分配给程序
  • 最坏适应(最大适应):按容量从大到小依次寻找空闲分区,将第一个能满足要求的空闲分区分配给程序
  • 邻近适应(循环首次适应):与首次适应类似,但是查找开始位置上一次查找结束的位置
  • 动态分区的分配策略的比较
    • 首次适应,简单,最好、最快

3.1离散内存分配方法(分页、分段、段页)


3.1.1分页

#####逻辑地址到物理地址的转换

逻辑地址到物理地址的转换(不含快表)

img


  • 设页面大小为 L,逻辑地址A 到物理地址E的转换
    1. 分析出页号和页面偏移量(根据题设地址结构或者计算得出):计算页号 P ( P = A / L )和页面偏移量 W (W = A % L )
    2. 判断页号合法性:比较页号 P 和页表长度 M ,若 PM ,则产生越界中断,否则继续执行。
    3. 查页表,得块号:页表中页号 P 对应的页表项地址(目的是在内存中找到相应的页表项) = 页表始址 F + 页号 P × 页表项长度,取出该页表项内容 b ,即为物理块号。(注意区分页表长度页表项长度页表长度的值指一共有多少页,页表项长度是指页地址占多大的存储空间)
    4. 拼接块号和页内偏移量:计算 E = b × L + W ,用得到的物理地址 E 去访问内存

逻辑地址到物理地址的转换(含快表)

img


  • 含快表的地址变换流程
    1. CPU 给出逻辑地址后,由硬件进行地址转换,将页号送入高速缓存寄存器,并将此页号与快表中的所有页号进行比较
    2. 若能找到匹配的页号,说明所要访问的页表项在快表中,则直接从中取出该页对应的块号,和页内偏移量拼接形成物理地址。(仅一次访存就可以存取数据)
    3. 若未找到,类似不含快表对逻辑地址进行转换,并把(页号,块号)对存入快表。若快表已满,则需依据相应的替换算法对快表中的元素进行替换

多级页表

  • 试和索引表比较一下
  • 多级和一级的对比
    • 一级页表,其存储页号到块号的存储极限取决于其本身的长度
    • 多级页表,其存储页号到块号的存储极限取决于各级页表长度之积
    • 总结:乘法比加法更能压缩空间
  • 以二级为例,分析其中的数据关系(注意举一反三)(★★★★★)
    • 32 位 逻辑地址空间、页面大小 4 KB、页表项 4 B,以字节为编址单位,试确定满足二级页表的逻辑地址空间格式(即求哪几位代表一级页号、二级页号、页内偏移)
      • 页内偏移位数 = log2页面大小log_2页面大小log2页面大小 (本例即 log24K=12log_24K=12log24K=12)
      • 由于顶级页表最多一个页面,故顶级(一级)页表总共能容纳 页面大小页表项大小页面大小/页表项大小 个页表项(本例为 4KB/4B = 1K),所需位数为 页表项个数log2(页表项个数)log_2(页表项个数)log2(页表项个数) (本例为log2(1K)=10log_2(1K)=10log2(1K)=10)
      • 剩下的 10 位,即为二级页号。
      • 所以逻辑地址空间格式如下

一级页号(10 位)二级页号(10 位)页内偏移量(12 位)

3.1.2分段(两次访存)

img


  • 逻辑地址A到物理地址E的转换
    1. 提取段号和页内偏移量:逻辑地址 A 的结构:前几位是段号 S ,后几位是段内偏移 W
    2. 判断段号合法性:比较段号 S 和段表长度 M ,若 SM ,则产生越界中断,否则继续执行
    3. 查段表,找到段基址、段长,并判段内偏移的合法性:段表中段号 S 对应的段表项地址 = 段表首址 F + 段号 S × 段表项长度,取出该段表项的前几位得到段长 C 。若段内偏移量 ≥ C,则产生越界中断,否则继续执行。
    4. 取出段基地址,和段内偏移求和:取出段表项中该段的基址 b ,计算 E = b + W

3.1.3段页(三次访存)

img


  • 逻辑地址A到物理地址E的变换

  1. 依据段号查段表,找到页表始址
  2. 依据页表始址页号查页表,得到块号
  3. 块号页面偏移量拼接成物理地址

3.2虚拟内存分配方法


虚拟内存

概念


虚拟记忆体是电脑系统记忆体管理的一种技术。它使得应用程式认为它拥有连续可用的记忆体(一个连续完整的位址空间),而实际上实体记忆体通常被分隔成多个记忆体碎片,还有部分暂时储存在外部磁碟记忆体上,在需要时进行资料交换。与没有使用虚拟记忆体技术的系统相比,使用这种技术使得大型程式的编写变得更容易,对真正的实体记忆体(例如RAM)的使用也更有效率。此外,虚拟记忆体技术可以使多个行程共享同一个执行库,并通过分割不同行程的记忆体空间来提高系统的安全性。



请求分页(段)管理

地址变换过程

img


页面置换算法


最佳(OPT)置换算法

  • 置换标准:淘汰最长时间内不再被访问的页面
  • 无法实现

先进先出(FIFO)置换算法

  • 置换标准:淘汰最早进入内存的页面(用队列实现)
  • 缺页率较高,会产生所分配的物理块数增大而页故障数反减的异常现象

最近最久未使用(LRU)置换算法

  • 置换标准:淘汰最近最久未使用的页面
  • 性能较好,但需要寄存器和栈的硬件支持。
  • 手算思路
    • 假想一个链表,其最大长度为内存中能存下最多页面的个数。
    • 若页面不在该链表中,且链表长度未超过最大长度,则将这个页面插入到链表头部
    • 若页面不在该链表中,且链表长度超过最大长度,则将链表末尾元素删除,并将新个页面插入到链表头部
    • 若页面在该链表中,则将新页面移动到链表头部,其他元素位置不变

时钟(CLOCK)置换算法(NRU,最近未用)

  • 置换标准:淘汰访问位为 0 的页面
    • (具体算法流程详见教材)
  • 改进的 CLOCK 算法:多增一位修改位。
    • 假设 A 为访问位, M 为修改位,(A, M)所有可能取值,淘汰顺序为
    • (0, 0) (0, 1) (1, 0) (1, 1) (优先换出未使用的;若全部都已使用,再考虑优先换出未被修改的)
    • (具体算法流程详见教材)

4.内存保护与共享

分段的共享和保护


共享段

为了实现分段共享,可在系统中配置一张共享段表,所有各共享段都在共享段表中占有一表项。表项中记录了共享段的段号、段长、内存.


分段保护

在分段系统中,由于每个分段在逻辑上是独立的,因而比较容易实现信息保护。目前常采用以下几种措施来确保信息的安全。


  1. 越界检查

    在段表寄存器中放有段表长度信息;同样,在段表中也为每个段设置有段长字段。在进行存储访问时,首先将逻辑地址空间的段号与段表长度

  2. 存取控制检查

    在段表的每个表项中,都设置了一个“存取控制”字段,用于规定对该段的访问方式。通常的访问方式有

  3. 环保护机构

    image-20220925154536831


5.抖动的概念和处理方法


概念


如果多道程度过高,页面在内存与外存之间频繁调度,以至于调度页面所需时间比进程实际运行的时间还多,此时系统效率急剧下降,甚至导致系统崩溃。这种现象称为颠簸或抖动(thrashing)



处理\预防方法


  • 采取局部置换策略
  • 在处理机调度中引入工作集策略
  • 用 L=S 准则调节缺页率(Denning, 1980)
  • 挂起若干进程

解题技巧与重要结论


  • 物理地址 VS 逻辑地址
    • 物理地址(实地址),若其位数为 32 位,意味着实际物理内存为 2322^{32}232B
    • 逻辑地址(虚地址),若其位数为 48 位,意味着对用户来说内存大小为 2482^{48}248B (采用了虚拟内存技术)
  • 含多级页表的逻辑地址的划分中的公式总结(对照教材中多级页表理解)
  • 页内偏移位数页面大小页内偏移位数=log2页面大小log_2页面大小log2页面大小
  • 页号部分总位数逻辑地址总位数页内偏移位数页号部分总位数=逻辑地址总位数逻辑地址总位数逻辑地址总位数页内偏移位数页内偏移位数页内偏移位数
  • 一级页号位数=页面大小页表项大小\frac{页面大小}{页表项大小}页表项大小页面大小
  • 页表级数=页号部分总位数一级页号位数\frac{页号部分总位数}{一级页号位数}一级页号位数页号部分总位数

推荐阅读
  • 深入剖析JVM垃圾回收机制
    本文详细探讨了Java虚拟机(JVM)中的垃圾回收机制,包括其意义、对象判定方法、引用类型、常见垃圾收集算法以及各种垃圾收集器的特点和工作原理。通过理解这些内容,开发人员可以更好地优化内存管理和程序性能。 ... [详细]
  • 深入理解Java多线程并发处理:基础与实践
    本文探讨了Java中的多线程并发处理机制,从基本概念到实际应用,帮助读者全面理解并掌握多线程编程技巧。通过实例解析和理论阐述,确保初学者也能轻松入门。 ... [详细]
  • 本文深入探讨了MySQL中常见的面试问题,包括事务隔离级别、存储引擎选择、索引结构及优化等关键知识点。通过详细解析,帮助读者在面对BAT等大厂面试时更加从容。 ... [详细]
  • 本文详细探讨了Java中Volatile关键字的工作原理、优化技巧及其在实际开发中的应用场景,特别是在提高多线程环境下数据可见性和减少锁竞争方面的优势。 ... [详细]
  • 如何使用 CleanMyMac X 2023 激活码解锁完整功能
    本文详细介绍了如何使用 CleanMyMac X 2023 激活码解锁软件的全部功能,并提供了一些优化和清理 Mac 系统的专业建议。 ... [详细]
  • 精选多款高效实用软件及工具推荐
    本文介绍并推荐多款高效实用的软件和工具,涵盖系统优化、网络加速、多媒体处理等多个领域,并提供安全可靠的下载途径。 ... [详细]
  • 本文详细阐述了云主机流量的概念,探讨其对网站性能和安全的关键影响,并提供了优化配置的实用建议。 ... [详细]
  • 本文探讨了如何通过一系列技术手段提升Spring Boot项目的并发处理能力,解决生产环境中因慢请求导致的系统性能下降问题。 ... [详细]
  • 本文档汇总了Python编程的基础与高级面试题目,涵盖语言特性、数据结构、算法以及Web开发等多个方面,旨在帮助开发者全面掌握Python核心知识。 ... [详细]
  • 深入解析BookKeeper的设计与应用场景
    本文介绍了由Yahoo在2009年开发并于2011年开源的BookKeeper技术。BookKeeper是一种高效且可靠的日志流存储解决方案,广泛应用于需要高性能和强数据持久性的场景。 ... [详细]
  • 前言无论是对于刚入行工作还是已经工作几年的java开发者来说,面试求职始终是你需要直面的一件事情。首先梳理自己的知识体系,针对性准备,会有事半功倍的效果。我们往往会把重点放在技术上 ... [详细]
  • 本文探讨了大型服务端开发过程中常见的几个误区,包括异步任务处理不当、日志同步模式使用、网络操作未设置超时、缓存命中率及响应时间未统计、单一缓存模式、分布式缓存加锁不当以及团队管理上的误区,旨在帮助开发者避免这些常见错误。 ... [详细]
  • 本文将详细介绍多个流行的 Android 视频处理开源框架,包括 ijkplayer、FFmpeg、Vitamio、ExoPlayer 等。每个框架都有其独特的优势和应用场景,帮助开发者更高效地进行视频处理和播放。 ... [详细]
  • 在高并发需求的C++项目中,我们最初选择了JsonCpp进行JSON解析和序列化。然而,在处理大数据量时,JsonCpp频繁抛出异常,尤其是在多线程环境下问题更为突出。通过分析发现,旧版本的JsonCpp存在多线程安全性和性能瓶颈。经过评估,我们最终选择了RapidJSON作为替代方案,并实现了显著的性能提升。 ... [详细]
  • vivo Y5s配备了联发科Helio P65八核处理器,这款处理器采用12纳米工艺制造,具备两颗高性能Cortex-A75核心和六颗高效能Cortex-A55核心。此外,它还集成了先进的图像处理单元和语音唤醒功能,为用户提供卓越的性能体验。 ... [详细]
author-avatar
肥zi斌_343
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有