zoukankan      html  css  js  c++  java
  • 操作系统之内存管理(一)(未引入虚拟内存之前部分)

    知识框架:



    一、内存管理的概念

    虽然计算机硬件一直飞速发展,但仍然不可能把所有用户进程和操作系统所需的全部东西放入主存中,所以操作系统必须将内存空间进行合理的划分和有效地动态分配。


    操作系统对内存的划分和动态分配,就是内存管理的概念


    内存管理的功能有:

    *内存空间的分配与回收

    *地址转换

    *内存空间的扩充

    *存储保护


    进行具体的内存管理前,了解进程运行的基本原理和要求(3个)


    1.程序装入

    创建进程首先要将程序和数据装入内存。将用户的源程序变为可在内存中执行的程序,通常需要以下几个步骤。

    (1)编译成若干目标模块

    (2)链接形成装入模块

    根据链接的时间分为静态链接、装入时动态链接(边装入边链接)、运行时动态链接

    (3)装入内存运行

    装入内存时也分为三种:


    **绝对装入:

    编译程序时产生绝对地址,按照绝对地址装入内存。程序中的逻辑地址和物理地址完全相同,只适用于单道程序环境。

    **可重定位装入:

    目标模块起始地址都是从0开始,程序中其他地址都是相对于起始地址的,根据内存的当前情况,将装入模块装入适当的位置。

    装入时对目标程序的指令和数据的修改过程称为重定位。

    地址变换在装入时一次完成,也称为静态重定位。内存不够不能装入,能装入也不能移动和申请内存,

    **动态运行时装入:

    也成为动态重定位,程序在内存中如果发生移动,就需要采用动态的装入方式。装入模块装入内存后并不立即吧相对地址转为绝对地址,而是推迟到真正执行时才进行。因此装入后均为相对地址,需要一个重定位寄存器的支持。


    2.逻辑地址空间与物理地址空间

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

    物理地址空间是指内存中物理单元的集合,它是地址转换的最终地址。


    3.内存保护

    需要保护操作系统不受用户进程的影响,同时保护用户进程不受其他用户进程的影响。可采取两种方法。

    **在CPU中设置一对上、下限寄存器,存放用户作业在主存中的下限和上限地址,每当CPU要访问一个地址时,分别和两个寄存器的值相比,判断有无越界。

    **采用重定位寄存器(或基址寄存器)和界地址寄存器(又称限长寄存器)来实现。基址和限长寄存器方法,采用基址和限长寄存器分别存放作业的起始地址及作业的地址空间长度。当作业执行时,将每一个访问内存的相对地址和限长寄存器比较,如果超过了限长寄存器的值,则发出越界中断信号,并停止作业的运行。


    二、覆盖与交换

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

    1.覆盖

    把用户空间分为一个固定区和若干个覆盖区。将经常活跃的部分放在固定区,其余部分按调用关系分段。首先将那些即将要访问的段放入覆盖区,其他的段放在外存中,在需要调用前,系统再将其调入覆盖区,替换覆盖区中原有的段

    2.交换

    交换:把处于等待状态(或在CPU调度规则下被剥夺运行权利)的程序从内存移到辅存(即外存),把内存空间腾出来,这过程叫换出;把准备好竞争CPU运行的程序从外存移到内存,这过程叫换入。

    3.交换技术主要是在不同进程(或作业)之间进行,而覆盖则用于同一个程序或进程中。


    三、连续分配管理方式

    连续分配方式,是指一个用户程序分配一个连续的内存空间。


    1.单一连续分配

    在此方式下,分为系统区和用户区,系统区通常在低地址部分,用户区是为用户提供的、除系统区之外的内存空间。没了。最简陋。


    2.固定分区分配

    将用户内存空间划分为若干个固定大小的区域,每个分区只装入一道作业。

    划分时有两种不同的方法:分区大小相等、分区大小不等。

    这种分区方式存在两个问题:

    (1)程序可能太大,放不进任何一个分区,这时不得不使用覆盖技术来使用内存。

    (2)主存利用率低,当程序小于固定分区大小时,也占用一个分区,分区内部有空间浪费,这种叫作内部碎片


    很少用于现代通用的操作系统中。


    3.动态分区分配

    又称为可变分区分配,是一种动态划分内存的分区方法。不预先将内存划分,而是进程装入内存时,根据进程的大小动态地建立分区,并使分区的大小刚好合适。


    在刚开始分配是很好的,但是之后会导致内存中出现许多小的内存块(大程序结束后,大分区还在,此时放入小程序产生碎片)。随着时间推移会越来越多,称为外部碎片。与固定分区的内部碎片相对。


    内部碎片:分配给进程的分区中未被利用的碎片称为内部碎片; 外部碎片:而系统中剩余的无法利用的小块存储空间称为外部碎片。


    克服外部碎片可通过紧凑技术来解决,就是系统不时对进程进行移动和整理,需要动态重定位寄存器支持,且费时。



    进程装入或换入内存时,OS必须确定分配哪个内存块给进程使用,这就是动态分区的分配策略:

    (1)首次适应法:顺序查找,选择第一个能满足要求的空闲分区。

    (2)最佳适应法:按容量递增形成分区链,找到第一个能满足的。(挑出最小且合适的)

    (3)最坏适应法:按容量递减形成分区链,找到第一个能满足的。(挑出最大的)

    (4)邻近适应法:首次适应演变而来。不同之处是接着上次查找结束的位置继续查找。


    上面几种里,首次适应法是最简单的,而且通常也是最好最快的


    四、非连续分配管理方式

    在之前的连续内存分配里,可以发现一个问题,即使有1G空闲空间,如果不连续,仍然是无法装入的。


    非连续分配管理方式允许一个程序分散地装入到不相邻的内存分区中。当然,这需要额外的空间去存储他们(分散区域)的索引,使得存储密度低于连续存储方式。


    非连续分配管理方式根据分区的大小是否固定分为分页存储管理(又根据是否把作业的所有页面都装入内存才能运行分为基本分页存储管理和请求分页存储管理)和分段存储管理方式。


    1.基本分页存储管理方式

    固定分区会产生内部碎片,动态分区会产生外部碎片,这两种技术对内存的利用率都比较低。为了尽量避免碎片的产生,引入了分页的思想把主存空间划分为大小相等且固定的块,作为主存基本单位。每个进程也以块为单位划分,执行时,以块为单位申请空间。


    分页方法从形式上看,和分区相等的固定分区技术很像,以及都不会产生外部碎片。但是不同的是,块大小比分区小很多,而且进程也按照块划分分散装入主存中的基本单位块。只会在程序最后一个块产生非常小的内部碎片(也称页内碎片)。


    (1)分页存储的几个基本概念

    **页面和页面大小

    进程中的块称为页,内存中的块称为页框或页帧。外存也以同样的单位进行划分,直接称为块。它们之间一一对应。

    **地址结构,如图


    **页表

    为了在内存中找到进程的每个页面对应的物理块,系统为每个进程建立一张页表,记录页面在内存中对应的物理块号,页表一般放到内存中。看下图,注意和地址结构区分。


    有了页表后,进程执行时,通过查找该表即可找到每页在内存中的物理块号。


    (2)基本地址变换机构

    地址变换机构的任务是将逻辑地址转换为内存中的物理地址,这个地址变换是借助于页表实现的。


    系统中通常设置一个页表寄存器(PTR),存放页表在内存的开始地址和页表长度。进程未执行时,页表的开始地址和长度都放在进程控制块(PCB)中,进程执行时才放入页表寄存器PTR。


    分页管理方式存在的两个问题:

    *地址转换过程必须够快,否则访存速度会降低(为此提出了快表TLB)

    *页表不能太大,否则内存利用率会降低(为此提出了两级页表)


    (3)具有快表的地址变换机构

    由上面的地址变换可知,存取一个数据或指令至少访问两次内存,一次是访问页表,另一次才是真访问,显然这种方法比通常慢了一半。


    为此,在地址变换机构中增设了一个高速缓冲器——快表,又称联想寄存器(TLB),用来存放若干页表项,加快速度。与此对应,主存中的页表常称慢表。如下:


    一般快表的命中率达到90%以上。快表的有效性是基于著名的局部性原理。将在虚拟内存中讨论。


    (4)两级页表

    实际中,如果按照一级页表那将会产生大量页表项,书上给出的例子算出得有100万个页表项。所以推出二级页表,而且二级页表(如果10个),那么也不需要都放在内存中,一部分常用的即可,需要再从外存调。

    二级页表实际上就是在原有的页表结构上再加了一层页表。

    顶级页表最多只能有一个页面,建立多级页表的目的在于索引,这样就不用浪费空间去存储无用的页表项,也不用盲目地顺序查找页表项了。


    2.基本分段存储管理方式

    分页管理方式是从计算机的角度考虑的,以提高内存利用率、性能且对用户透明。而分段管理方式的提出则是考虑了用户和程序员,以方便编程、信息保护与共享、动态增长等需求。


    (1)分段

    按照用户进程中的自然段划分逻辑空间。例如用户进程由主程序、两子程序、栈和数据组成,那么就可以划分为5个段,段内要求连续,段间不要求连续。逻辑地址如下


    页式系统中逻辑地址的页号和偏移量对用户是透明的,但在段式系统中,段号和段内偏移量必须由用户显式提供,在高级程序设计语言中,这个工作由编译程序完成。

    (2)段表

    每个进程都有一张逻辑空间与内存空间的映射的段表,其中每个段表项对应进程的一个段,记录起始地址和长度,段表如下:


    (3)地址变换机构


    (4)段的共享与保护

    分段系统中,段的共享是通过两个作业的段表对应同个物理地址


    3.段页式管理方式

    页式提高内存利用率,段式反映程序的逻辑结构并有利于段共享,而段页式管理是结合这两种方式。

    段页式系统中,作业的地址空间首先被分成若干个逻辑段,每段都有自己的段号,然后再将每一段分成若干个大小固定的页。对内存的管理仍和分页存储管理一样,将其分成若干个和页面大小相同的存储块,对内存的分配以存储块为单位。如下:


    地址结构:


    首先通过段表查到页表起始地址(是哪个页表),然后通过用段内页号在页表找到块号,最后用块号结合偏移量形成物理地址,如下图:


  • 相关阅读:
    [LeetCode] 1019. Next Greater Node In Linked List 链表中的下一个较大的结点
    [LeetCode] 1018. Binary Prefix Divisible By 5 可被5整除的二进制前缀
    [LeetCode] 1017. Convert to Base -2 负二进制转换
    [LeetCode] 1016. Binary String With Substrings Representing 1 To N 子串能表示从1到N数字的二进制串
    [LeetCode] 1015. Smallest Integer Divisible by K 可以整除K的最小整数
    [LeetCode] 1014. Best Sightseeing Pair 最佳观光组合
    [LeetCode] 1013. Partition Array Into Three Parts With Equal Sum 将数组分成和相等的三个部分
    [LeetCode] 1012. Numbers With Repeated Digits 至少有1位重复的数字
    [LeetCode] 1011. Capacity To Ship Packages Within D Days 在D天内送达包裹的能力
    [LeetCode] 1010. Pairs of Songs With Total Durations Divisible by 60 总持续时间可被60整除的歌曲
  • 原文地址:https://www.cnblogs.com/chz-blogs/p/9381006.html
Copyright © 2011-2022 走看看