精华内容
下载资源
问答
  • 在linux操作系统内存管理中,主要就是管理内核内存(包括驱动的内存)和进程内存,在大内存的机器上,大量的物理内存无法一一映射进内核地址空间的前HIGH兆,因此实际上对于大多数内核内存管理来讲,这些大量的内存...

    struct pglist_data {
        struct zone node_zones[MAX_NR_ZONES];
        struct zonelist node_zonelists[GFP_ZONETYPES];
    ...
    }
    GFP_ZONETYPES是一个宏,在2.6.8的时候它如下定义:
    #define GFP_ZONEMASK    0x07
    /* #define GFP_ZONETYPES       (GFP_ZONEMASK + 1) */      
    #define GFP_ZONETYPES  ((GFP_ZONEMASK + 1) / 2 + 1)
    也就是说每一个numa的node拥有算了一下5条zone链表,就这还算比较少了。
    可是在高一点版本的内核中,这个本来已经很低的zonelists数量变成了2(支持numa)或者1(不支持numa),也许很多人会说,通过GFP标志已经无法控制在哪个zone中以及之下分配内存了,然而看一下get_page_from_freelist这个函数多了很多参数,其中一个high_zoneidx所起到的作用就是原来那么多zonelist的作用,由此可见,高版本的内核丝毫没有降低功能,倒是少维护很多链表。以下首先说一下早期的内核中的多条zonelist链表的起因以及为何那么设计。
         在早期的内核中,每一个node拥有好几条zonelist,每一条代表一个起始zone开始的以及其下的所有的zone,但是这只是实际上的做法,而理论上这个zonelist的数量会更多,这些zonelist代表了一个优先级序列,说明了内存分配在zone中尝试的顺序,在实现中,linux是用位掩码来实现的。如果我们有三个zone,那么就应该用3位掩码中的每一个位来表示不同的zone掩码,设如下:
    0x01表示dma
    0x02表示normal
    0x04表示highmem
    这样3个位就有8*2...个顺序,分别是(o为空):
    1.o;
    2.dma;
    3.normal->o;
    4.normal->dma;
    5.highmem->o;
    6.highmem->o->dma;
    7.highmem->normal->o;
    8.highmem->normal->dma;
    9-16.前面8个方向反过来。
    17-xx.两两反向,保持一个正向...
    可是为何内核仅仅保留了3个左右的顺序呢?首先是三个原则在起作用,第一个就是一致的顺序管理起来更高效而且更不容易冲突,类似单行道的作用,虽然灵活性不够!第二个原则就是内核的内存管理是一个管理机构,但凡内核的管理机构,采取的原则都是平等至上的!第三个原则就是连续性管理原则,按照一定的顺序依次编排,这个顺序一般都是从易到难,从受影响最小的地方开始,不到万不得已不会惊动其它。有了这三个原则的话,首先我们看一下为何没有反向顺序的zonelist,如果有的话就增加了管理负担,因为自动内存置换程序(kswapd)和手动置换程序(try_to_free...)就都要在两个方向进行扫描和管理,由于存在多条路径扫描和分配,这就很不容易了解到各个zone的内存使用情况,从而不知道要将扫描主力放在哪个zone。那么为何不存在跳跃的zonelist,比如跳过normal而仅仅在highmem和dma中分配,这是因为之所以存在一个zonelist而不是一个zone是因为在该zone中分配失败之后有一个后备的可分配zone,由于分配使用的zonelist使用的顺序必然是从容易分配的zone到难分配的zone排列的,那么dma中分配内存的代价会比normal中分配的代价更大。在linux操作系统的内存管理中,主要就是管理内核内存(包括驱动的内存)和进程内存,在大内存的机器上,大量的物理内存无法一一映射进内核地址空间的前HIGH兆,因此实际上对于大多数内核内存管理来讲,这些大量的内存对之意义不大,因此它们更多的被用于进程内存,进程内存是可以随意映射进自己的地址空间的,不要求映射的方式--比如线性映射,也不要求连续性。因此进程内存优先从highmem这个zone中分配,如果不行的话,则最好先在normal中看看,然后再往dma走。对于内核内存管理而言,在系统初始化的时候,一些核心的数据和代码已经映射完毕了,需要内存的大户都是驱动或者模块或者就是诸如进程管理和网络协议栈的动态部分,比如新申请了一个task_t结构体,或者新分配了一个sk_buff结构体等等,这些内存一般从normal区开始分配,这是因为使用normal区的内存可以线性映射进系统内核,操作起来更高效。由于没有谁拥有特权,所以大家都遵守一样的原则,从它所可以触及的最高zone(gfp_flags决定)依次尝试到最低的zone,如果不行则手工调用try_to_free...从该zonelist的开始zone开始释放一些内存,这样做真的是很简单很高效!内核之所以不通知用户进程和驱动就直接在某个zone为之分配了内存是因为zone是操作系统内存管理模块最低层的概念,进程或者驱动甚至都不应该知道有zone的存在,因此内核才可以采取遵循以上三个原则的策略将物理内存分为若干个zone,然后按照从高到低的顺序依次尝试分配内存,直到成功。
         后期的内核将上述机制的实现改变了,每一个pglist_data在没有numa的情况下只有一条zonelist,按照上述的三个原则,其实没有必要搞那么多链表的,由于不存在跳跃,不存在逆向,因此只需要一个链表和一个上限值即可,每次分配内存的时候从这个上限值代表的zone往下开始尝试即可,这样就可以省去一些空间和管理费用,将事先设置好N条zonelist转为直到实际上分配内存的时候再确定上限:
    struct page *__alloc_pages_nodemask(gfp_t gfp_mask, unsigned int order,
                struct zonelist *zonelist, ...)
    { //参数中的zonelist其实就是那唯一的一条zonelist(没有numa的情况下)
        enum zone_type high_zoneidx = gfp_zone(gfp_mask);
    ...
    }
    如此一来,high_zoneidx这个变量就可以作为一个限制值,在get_page_from_freelist的时候设置一个阀值,虽然__alloc_pages_nodemask函数增加了一些分量,但是时间一点也不损耗多少,取消了几个链表,运行时增加了几个指令周期,这也许(很可能)是值得的。

    展开全文
  • 操作系统-内存管理

    万次阅读 多人点赞 2019-06-06 09:20:53
  • 内存与操作系统内存管理

    千次阅读 2021-02-28 15:10:12
    内存与操作系统内存管理 文章目录内存与操作系统内存管理一、内存的基础知识二、内存管理2.1 内存空间扩充2.2 内存空间的分配与回收 一、内存的基础知识   内存是用于存放数据的硬件,程序执行前需要将数据放入...

    内存与操作系统内存管理



    Java、大数据开发学习要点(持续更新中…)


    一、内存的基础知识

      内存是用于存放数据的硬件,程序执行前需要将数据放入内存中才能被CPU处理。内存通过对内部的存储单元编址来解决并发执行下各个程序的数据区分,根据计算机字长的不同,存储单元大小不同(如64位计算机每个字大小为64位,8个字节)。
      内存存放的相对寻址:编译语言编译后的指令寻址,是通过相对地址实现的,实际存入内存时再根据进程在内存中的起始地值得到绝对地址。编译生成的机器语言中的地址实际都是逻辑地址,再通过链接(形成完整逻辑地址)后,通过装入模块装入内存运行,这时将逻辑地址转换成物理地址(主要使用动态重定位装入方法:CPU内有重定位寄存器保存了程序存放内存的起始位置,结合逻辑地址可以实现动态重定位)。

    二、内存管理

      操作系统是系统资源的管理者,也需要对内存进行管理。操作系统需要负责以下事情:

    1. 提供某种技术从逻辑上对内存空间进行扩充
    2. 内存空间的分配与回收
    3. 提供地址转换功能,负责程序从逻辑地址到物理地址的转换(动态重定位,依赖于重定位寄存器)
    4. 提供内存保护功能,保证各个进程在各自存储空间内运行,互不干扰。

    2.1 内存空间扩充

      操作系统对内存空间的扩充主要有覆盖技术、交换技术和虚拟存储技术(后面详细介绍):

    • 覆盖技术:用于早期操作系统中。
    • 交换技术:实际就是进程调度中的内存调度,进程在内存和磁盘间动态调度(进程未结束前内存中始终保留PCB信息)。进程从内存中被换出是保存在磁盘的对换区中(这个区域I/O速度比文件区快,详细在文件部分讲解)。

    2.2 内存空间的分配与回收**

      内存空间分配分为连续分配管理方式和非连续分配管理方式:

    (1)连续分配管理方式中又分为单一连续分配、固定分区分配和动态分区分配

    • 单一连续分配,只适用于单任务操作系统。
    • 固定分区分配,将内存中除了系统区外的用户空间分为固定大小或大小不等的分区,并建立分区说明表的数据结构(数组或链表)记录每个分区大小、起始地址、状态等信息,缺点在于用户程序过大需要覆盖技术支持,且会产生内部碎片。
    • 动态分区分配,在进程装入内存时,动态地建立分区。操作系统使用空闲分区表或空闲分区链来记录内存使用情况(分区号、分区大小、起始地址等)。
      常用记录内存使用情况的数据结构
      而当新的进程要装入内存时,需要用动态分区分配算法来选择出一个合适的分区。

    (2)非连续分配管理方式为用户进程分配的可以是一些分散的内存空间,主要管理方式有分页存储管理分段存储管理段页式存储管理

    • 分页存储管理:将内存空间分为大小相等的小分区,每个分区称为页框,编号从0开始。相应地,将用户进程的地址空间也分为 与页框大小相等 的一个个区域,每个部分称为,编号同样从0开始。(注:进程的最后一个页可能没有一个页框那么大,因此页框不能过大,否则可能产生过大的内部碎片)
        那么分页存储是离散存储的,如何实现逻辑地址到物理地址的转换?
        将动态重定位的思想使用到分页存储中,首先计算逻辑地址对应的页号(逻辑地址/页面大小)和页内偏移量(逻辑地址%页面大小),得到该页号在内存中存放的起始地址,由此物理地址=页面地址+页内偏移量。而要知道进程的每个页在内存中存放的位置,操作系统需要为每个进程建立一张页表
      分页基本地址变化过程
    • 分段存储管理按照程序自身逻辑关系划分为若干个段,每个段有一个段名,每段从0开始编址。每个段在内存中占据连续空间,但各个段之间可以不相邻。与分页存储类似,操作系统在分段存储时为每个进程建立一张段表来保存各个段离散装入内存对应的段长、基址(与分页相似,段表项长度相同,可以通过段表计算段号,所以段号是隐含的不占存储空间)等信息。分段存储管理逻辑地址到物理地址的转换如下图:
      分段基本地址变化过程
      可以看出分段存储中由于每个段的长度都不同,因此对比分页存储多了段内地址越界检查。
    • 分段与分页的对比
    1. 信息的物理单元对用户不可见,信息的逻辑单元对用户可见。
    2. 大小固定且由系统决定长度不固定且决定于用户编写的程序
    3. 分页用户进程地址是一维的(只需要一个记忆符),分段用户进程地址是二维的(需要给出段名和段内地址)。
    4. 分段更容易实现信息的共享和保护(只能共享不属于临界资源的代码),当需要让内存中的某个片段共享给多个进程,只需要将各个进程的段表指向同一个段即可。
    • 加快分页过程
    1. 如何提高逻辑地址和物理地址的映射速度?(快表)
        系统一旦访问了某一个页,就会在一段时间内稳定工作在这个页上。所以为了提高访问页表的速度,计算机配备了一组能容纳部分页表的硬件寄存器。当系统再次需要将地址转换时,先访问这组硬件寄存器(即,快表)。
    2. 页表过大怎么解决?
        页表存在的问题是,页表必须连续存放在多个连续的页框中,页表过大时离散存储失去了其本质意义,所以可以再建一级索引(二级页表)来让原页表连续页表项分组离散存储。

    参考:《王道考研操作系统》
    地址:https://www.bilibili.com/video/BV1YE411D7nH

    展开全文
  • 操作系统内存管理(思维导图详解)

    万次阅读 多人点赞 2010-07-05 11:26:00
    在介绍内存管理的细节前,先要了解一下分层存储器体系: 大部分的计算机都有一个存储器层次结构,即少量的非常快速、昂贵、易变的高速缓存(cache);若干兆字节的中等速度、中等价格、易变的主存储器(RAM);...

    操作系统内存管理:总的来说,操作系统内存管理包括物理内存管理和虚拟内存管理。

    物理内存管理:

           包括程序装入等概念、交换技术、连续分配管理方式和非连续分配管理方式(分页、分段、段页式)。

    虚拟内存管理:
          虚拟内存管理包括虚拟内存概念、请求分页管理方式、页面置换算法、页面分配策略、工作集和抖动。

          这个系列主要使用linux内存管理来具体说明:linux内存管理

     

    一、 计算机的存储体系


    内存是计算机很重要的一个资源,因为程序只有被加载到内存中才可以运行;此外,CPU所需要的指令与数据也都是来自内存的。可以说,内存是影响计算机性能的一个很重要的因素。

    分层存储器体系

    在介绍内存管理的细节前,先要了解一下分层存储器体系:

    大部分的计算机都有一个存储器层次结构,即少量的非常快速、昂贵、易变的高速缓存(cache);若干兆字节的中等速度、中等价格、易变的主存储器(RAM);数百兆或数千兆的低速、廉价、不易变的磁盘。这些资源的合理使用与否直接关系着系统的效率。

    CPU缓存(Cache Memory):是位于CPU与内存之间的临时存储器,它的容量比内存小的多但是交换速度却比内存要快得多。缓存的出现主要是为了解决CPU运算速度与内存 读写速度不匹配的矛盾,因为CPU运算速度要比内存读写速度快很多,这样会使CPU花费很长时间等待数据到来或把数据写入内存。

    计算机是一种数据处理设备,它由CPU和内存以及外部设备组成。CPU负责数据处理,内存负责存储,外部设备负责数据的输入和输出,它们之间通过总线连接在一起。CPU内部主要由控制器、运算器和寄存器组成。控制器负责指令的读取和调度,运算器负责指令的运算执行,寄存器负责数据的存储,它们之间通过CPU内的总线连接在一起。每个外部设备(例如:显示器、硬盘、键盘、鼠标、网卡等等)则是由外设控制器、I/O端口、和输入输出硬件组成。外设控制器负责设备的控制和操作,I/O端口负责数据的临时存储,输入输出硬件则负责具体的输入输出,它们间也通过外部设备内的总线连接在一起。

    上面计算机系统结构图中我们可以看出硬件系统的这种组件化的设计思路总是贯彻到各个环节。

     在这套设计思想(冯.诺依曼体系架构)里面:  总是有一部分负责控制、一部分负责执行、一部分则负责存储,它之间进行交互以及接口通信则总是通过总线来完成。这种设计思路一样的可以应用在我们的软件设计体系里面:组件和组件之间通信通过事件的方式来进行解耦处理,而一个组件内部同样也需要明确好各个部分的职责(一部分负责调度控制、一部分负责执行实现、一部分负责数据存储)。

     

    计算存储的层次结构

    当前技术没有能够提供这样的存储器,因此大部分的计算机都有一个存储器层次结构:

    高速缓存(cache): 少量的非常快速、昂贵、易变的高速缓存(cache);

    主存储器(RAM): 若干兆字节的中等速度、中等价格、易变的主存储器(RAM);

    磁盘:  数百兆或数千兆的低速、廉价、不易变的磁盘。

    这些资源的合理使用与否直接关系着系统的效率。

     

    二、内存使用演化


    1、没有内存抽象的年代

    在早些的操作系统中,并没有引入内存抽象的概念。程序直接访问和操作的都是物理内存,内存的管理也非常简单,除去操作系统所用的内存之外,全部给用户程序使用,想怎么折腾都行,只要别超出最大的容量。比如当执行如下指令时:mov reg1,1000

    1、无内存抽象存在的问题:

    这条指令会毫无想象力的将物理地址1000中的内容赋值给寄存器。不难想象,这种内存操作方式使得操作系统中存在多进程变得完全不可能,比如MS-DOS,你必须执行完一条指令后才能接着执行下一条。如果是多进程的话,由于直接操作物理内存地址,当一个进程给内存地址1000赋值后,另一个进程也同样给内存地址赋值,那么第二个进程对内存的赋值会覆盖第一个进程所赋的值,这回造成两条进程同时崩溃。

    带来两个问题:

    1. 用户程序可以访问任意内存,容易破坏操作系统,造成崩溃

    2. 同时运行多个程序特别困难

    随着计算机技术发展,要求操作系统支持多进程的需求,所谓多进程,并不需要同时运行这些进程,只要它们都处于 ready 状态,操作系统快速地在它们之间切换,就能达到同时运行的假象。每个进程都需要内存,Context Switch 时,之前内存里的内容怎么办?简单粗暴的方式就是先 dump 到磁盘上,然后再从磁盘上 restore 之前 dump 的内容(如果有的话),但效果并不好,太慢了!

    2、内存抽象:地址空间

    那怎么才能不慢呢?把进程对应的内存依旧留在物理内存中,需要的时候就切换到特定的区域。这就涉及到了内存的保护机制,毕竟进程之间可以随意读取、写入内容就乱套了,非常不安全。因此操作系统需要对物理内存做一层抽象,也就是「地址空间」(Address Space),一个进程的地址空间包含了该进程所有相关内存,比如 code / stack / heap。一个 16 KB 的地址空间可能长这样:

    当程序运行时,heap 和 stack 共用中间 free 的区域,当然这只是 OS 层面的抽象。比如下面这段代码:

    int x;
    
    x = x + 3; // this is the line of code we are interested in

    变成汇编指令后,大概是这样:

    128: movl 0x0(%ebx), %eax  ;load 0+ebx into eax
    132: addl $0x03, %eax ;add 3 to eax register
    135: movl %eax, 0x0(%ebx) ;store eax back to mem

    最前面的是 PC (Program Counter),用来表示当前 code 的索引,比如 CPU 执行到 128 时,进行了 Context Switch(上下文切换),那么在 Switch 回来后,还可以接着从 132 开始执行(当然需要先把 PC 存起来)。之后的就是汇编代码,告诉 CPU 该如何操作。

    从进程的角度看,内存可能是这样的:

    真实的物理内存可能是这样的:

    基址寄存器与界限寄存器可以简单的动态重定位:每个内存地址送到内存之前,都会自动加上基址寄存器的内容。

    从 32KB 处作为开始,48KB 作为结束。那 32 / 48 可不可以动态设置呢,只要在 CPU 上整两个寄存器,基址寄存器base 和 界限寄存器bounds 就可以了,base 指明从哪里开始,bounds 指定哪里是边界。 因此真实物理地址和虚拟地址之间的关系是:

    physical address = virtual address + base

    有时,CPU 上用来做内存地址翻译的也会被叫做「内存管理单元 MMU」(Memory Management Unit),随着功能越来越强大,MMU 也会变得越来越复杂。

    base and bounds 这种做法最大的问题在于空间浪费,Stack 和 Heap 中间有一块 free space,即使没有用,也被占着,那如何才能解放这块区域呢,进入虚拟内存。

     

    3、虚拟内存

    虚拟内存是现代操作系统普遍使用的一种技术。前面所讲的抽象满足了多进程的要求,但很多情况下,现有内存无法满足仅仅一个大进程的内存要求。物理内存不够用的情况下,如何解决呢?

     覆盖overlays:在早期的操作系统曾使用覆盖技术来解决这个问题,将一个程序分为多个块,基本思想是先将块0加入内存,块0执行完后,将块1加入内存。依次往复,这个解决方案最大的问题是需要程序员去程序进行分块,这是一个费时费力让人痛苦不堪的过程。后来这个解决方案的修正版就是虚拟内存。
    交换swapping:可以将暂时不能执行的程序(进程)送到外存中,从而获得空闲内存空间来装入新程序(进程),或读人保存在外存中而处于就绪状态的程序。

    虚拟内存:虚拟内存的基本思想是,每个进程有用独立的逻辑地址空间,内存被分为大小相等的多个块,称为(Page).每个页都是一段连续的地址。对于进程来看,逻辑上貌似有很多内存空间,其中一部分对应物理内存上的一块(称为页框,通常页和页框大小相等),还有一些没加载在内存中的对应在硬盘上。

     

    三. 物理内存:连续分配存储管理方式


          连续分配是指为一个用户程序分配连续的内存空间。连续分配有单一连续存储管理和分区式储管理两种方式。

    3.1 单一连续存储管理

         在这种管理方式中,内存被分为两个区域:系统区和用户区。应用程序装入到用户区,可使用用户区全部空间。其特点是,最简单,适用于单用户、单任务的操作系统。CP/M和 DOS 2.0以下就是采用此种方式。这种方式的最大优点就是易于管理。但也存在着一些问题和不足之处,例如对要求内存空间少的程序,造成内存浪费;程序全部装入,使得很少使用的程序部分也占用—定数量的内存。

    3.2 分区式存储管理

           为了支持多道程序系统和分时系统,支持多个程序并发执行,引入了分区式存储管理。分区式存储管理是把内存分为一些大小相等或不等的分区,操作系统占用其中一个分区,其余的分区由应用程序使用,每个应用程序占用一个或几个分区。分区式存储管理虽然可以支持并发,但难以进行内存分区的共享。

           分区式存储管理引人了两个新的问题:内碎片和外碎片

          内碎片是占用分区内未被利用的空间,外碎片是占用分区之间难以利用的空闲分区(通常是小空闲分区)。

           为实现分区式存储管理,操作系统应维护的数据结构为分区表或分区链表。表中各表项一般包括每个分区的起始地址、大小及状态(是否已分配)。

          分区式存储管理常采用的一项技术就是内存紧缩(compaction)。

    3.2.1 固定分区(nxedpartitioning)。

            固定式分区的特点是把内存划分为若干个固定大小的连续分区。分区大小可以相等:这种作法只适合于多个相同程序的并发执行(处理多个类型相同的对象)。分区大小也可以不等:有多个小分区、适量的中等分区以及少量的大分区。根据程序的大小,分配当前空闲的、适当大小的分区。

          优点:易于实现,开销小。

          缺点主要有两个:内碎片造成浪费;分区总数固定,限制了并发执行的程序数目。

    3.2.2动态分区(dynamic partitioning)。

            动态分区的特点是动态创建分区:在装入程序时按其初始要求分配,或在其执行过程中通过系统调用进行分配或改变分区大小。与固定分区相比较其优点是:没有内碎片。但它却引入了另一种碎片——外碎片。动态分区的分区分配就是寻找某个空闲分区,其大小需大于或等于程序的要求。若是大于要求,则将该分区分割成两个分区,其中一个分区为要求的大小并标记为“占用”,而另一个分区为余下部分并标记为“空闲”。分区分配的先后次序通常是从内存低端到高端。动态分区的分区释放过程中有一个要注意的问题是,将相邻的空闲分区合并成一个大的空闲分区。

    下面列出了几种常用的分区分配算法:

            最先适配法(nrst-fit):按分区在内存的先后次序从头查找,找到符合要求的第一个分区进行分配。该算法的分配和释放的时间性能较好,较大的空闲分区可以被保留在内存高端。但随着低端分区不断划分会产生较多小分区,每次分配时查找时间开销便会增大。

           下次适配法(循环首次适应算法 next fit):按分区在内存的先后次序,从上次分配的分区起查找(到最后{区时再从头开始},找到符合要求的第一个分区进行分配。该算法的分配和释放的时间性能较好,使空闲分区分布得更均匀,但较大空闲分区不易保留。

           最佳适配法(best-fit):按分区在内存的先后次序从头查找,找到其大小与要求相差最小的空闲分区进行分配。从个别来看,外碎片较小;但从整体来看,会形成较多外碎片优点是较大的空闲分区可以被保留。

           最坏适配法(worst- fit):按分区在内存的先后次序从头查找,找到最大的空闲分区进行分配。基本不留下小空闲分区,不易形成外碎片。但由于较大的空闲分区不被保留,当对内存需求较大的进程需要运行时,其要求不易被满足。

    3.3 伙伴系统

            固定分区和动态分区方式都有不足之处。固定分区方式限制了活动进程的数目,当进程大小与空闲分区大小不匹配时,内存空间利用率很低。动态分区方式算法复杂,回收空闲分区时需要进行分区合并等,系统开销较大。伙伴系统方式是对以上两种内存方式的一种折衷方案。
            伙伴系统规定,无论已分配分区或空闲分区,其大小均为 2 的 k 次幂,k 为整数, l≤k≤m,其中:

            2^1 表示分配的最小分区的大小,

            2^m 表示分配的最大分区的大小,

            通常 2^m是整个可分配内存的大小。
            假设系统的可利用空间容量为2^m个字, 则系统开始运行时, 整个内存区是一个大小为2^m的空闲分区。在系统运行过中, 由于不断的划分,可能会形成若干个不连续的空闲分区,将这些空闲分区根据分区的大小进行分类,对于每一类具有相同大小的所有空闲分区,单独设立一个空闲分区双向链表。这样,不同大小的空闲分区形成了k(0≤k≤m)个空闲分区链表。 

           分配步骤:

           当需要为进程分配一个长度为n 的存储空间时:

           首先计算一个i 值,使 2^(i-1) <n ≤ 2^i,

           然后在空闲分区大小为2^i的空闲分区链表中查找。

           若找到,即把该空闲分区分配给进程。

           否则,表明长度为2^i的空闲分区已经耗尽,则在分区大小为2^(i+1)的空闲分区链表中寻找。

           若存在 2^(i+1)的一个空闲分区,则把该空闲分区分为相等的两个分区,这两个分区称为一对伙伴,其中的一个分区用于配,   而把另一个加入分区大小为2^i的空闲分区链表中。

           若大小为2^(i+1)的空闲分区也不存在,则需要查找大小为2^(i+2)的空闲分区, 若找到则对其进行两次分割:

                  第一次,将其分割为大小为 2^(i+1)的两个分区,一个用于分配,一个加入到大小为 2^(i+1)的空闲分区链表中;

                  第二次,将第一次用于分配的空闲区分割为 2^i的两个分区,一个用于分配,一个加入到大小为 2^i的空闲分区链表中。

          若仍然找不到,则继续查找大小为 2^(i+3)的空闲分区,以此类推。

          由此可见,在最坏的情况下,可能需要对 2^k的空闲分区进行 k 次分割才能得到所需分区。

          与一次分配可能要进行多次分割一样,一次回收也可能要进行多次合并,如回收大小为2^i的空闲分区时,若事先已存在2^i的空闲分区时,则应将其与伙伴分区合并为大小为2^i+1的空闲分区,若事先已存在2^i+1的空闲分区时,又应继续与其伙伴分区合并为大小为2^i+2的空闲分区,依此类推。
            在伙伴系统中,其分配和回收的时间性能取决于查找空闲分区的位置和分割、合并空闲分区所花费的时间。与前面所述的多种方法相比较,由于该算法在回收空闲分区时,需要对空闲分区进行合并,所以其时间性能比前面所述的分类搜索算法差,但比顺序搜索算法好,而其空间性能则远优于前面所述的分类搜索法,比顺序搜索法略差。 需要指出的是,在当前的操作系统中,普遍采用的是下面将要讲述的基于分页和分段机制的虚拟内存机制,该机制较伙伴算法更为合理和高效,但在多处理机系统中,伙伴系统仍不失为一种有效的内存分配和释放的方法,得到了大量的应用。

    3.4 内存紧缩(内存碎片化处理)

              内存紧缩:将各个占用分区向内存一端移动,然后将各个空闲分区合并成为一个空闲分区。

            这种技术在提供了某种程度上的灵活性的同时,也存在着一些弊端,例如:对占用分区进行内存数据搬移占用CPU时间;如果对占用分区中的程序进行“浮动”,则其重定位需要硬件支持。

              紧缩时机:每个分区释放后,或内存分配找不到满足条件的空闲分区时。

           

                                   图8.12

          堆结构的存储管理的分配算法:

          在动态存储过程中,不管哪个时刻,可利用空间都是-一个地址连续的存储区,在编译程序中称之为"堆",每次分配都是从这个可利用空间中划出一块。其实现办法是:设立一个指針,称之为堆指针,始终指向堆的最低(或锻联)地址。当用户申请N个单位的存储块时,堆指针向高地址(或 低地址)称动N个存储单位,而移动之前的堆指针的值就是分配给用户的占用块的初始地址。例如,某个串处理系统中有A、B、C、D这4个串,其串值长度分别為12,6,10和8. 假设堆指针free的初值为零,则分配给这4个串值的存储空间的初始地址分别为0.12.18和 28,如图8.12(a)和(b)所示,分配后的堆指针的值为36。 因此,这种堆结构的存储管理的分配算法非常简单

         释放内存空间执行内存紧缩:

         回收用户释放的空闲块就比较麻烦.由于系统的可利用空间始终是一个绝址连续的存储块,因此回收时必须将所释放的空间块合并到整个堆上去才 能重新使用,这就是"存储策缩"的任务.通常,有两种做法:

          一种是一旦有用户释放存储块即进行回收紧缩,例始,图8.12 (a)的堆,在c串释放存储块时即回收紧缩,例如图8.12 (c)的堆,同时修改串的存储映像成图8.12(d)的状态;

         另一种是在程序执行过程中不回收用户随时释放的存储块,直到可利用空同不够分配或堆指针指向最高地址时才进行存储紧缩。此时紧缩的目的是将堆中所有的空间块连成一块,即将所有的占用块部集中到 可利用空间的低地地区,而剩余的高地址区成为一整个地继连续的空闲块,如图8.13所示,其中(a)为紧缩前的状态,(b)为紧缩后的状态•

          

                         图8.13  a 紧缩前 b紧缩后

           和无用单元收集类似,为实现存储紫编,首先要对占用块进行“标志”,标志算法和无用单元收集类同(存储块的结构可能不同),其次需进行下列4步雄作:

          (1)计算占用块的新地址。从最低地址开始巡査整个存储空间,对每一个占用块找到它在紧缩后的新地址。 为此,需设立两个指针随巡查向前移动,这两个指针分别指示占用 块在紧缩之前和之后的原地址和新地址。因此,在每个占用块的第-·个存储单位中,除了 设立长度域(存储该占用换的大小)和标志域(存储区别该存储块是占用块或空闲块的标 志)之外,还需设立一个新地址城,以存储占用块在紧缩后应有的新地址,即建立一张新, 旧地址的对照表m

           (2)修改用户触初始变量表,以便在存储紧缩后用户程序能继续正常运行*。

           (3)检查每个占用块中存储的数据, 若有指向其他存储换的指针,则需作相应修改.

           (4)将所有占用块迁移到新地址走,这实质上是作传送数据的工作。

           至此,完成了存储紧缩的操作,最后,将堆指针赋以新值(即紧缩后的空闲存储区的最低地址)。

           可见,存储紧缩法比无用单元收集法更为复杂,前者不仅要传送数据(进行占用块迁移),而且还有需要修改所有占用块中的指针值。因此,存储紧缩也是个系统操作,且非不得已就不用。

     

    3.5 覆盖技术

            引入覆盖 (overlay)技术的目标是在较小的可用内存中运行较大的程序。这种技术常用于多道程序系统之中,与分区式存储管理配合使用。

           覆盖技术的原理:一个程序的几个代码段或数据段,按照时间先后来占用公共的内存空间。将程序必要部分(常用功能)的代码和数据常驻内存;可选部分(不常用功能)平时存放在外存(覆盖文件)中,在需要时才装入内存。不存在调用关系的模块不必同时装入到内存,从而可以相互覆盖。

           在任何时候只在内存中保留所需的指令和数据;当需要其它指令时,它们会装入到刚刚不再需要的指令所占用的内存空间;

           如在同一时刻,CPU只能执行B,C中某一条。B,C之间就可以做覆盖。

          

     

           覆盖技术的缺点是编程时必须划分程序模块和确定程序模块之间的覆盖关系,增加编程复杂度;从外存装入覆盖文件,以时间延长换取空间节省。

          覆盖的实现方式有两种:以函数库方式实现或操作系统支持。

    3.6 交换技术

          交换 (swapping)技术在多个程序并发执行时,可以将暂时不能执行的程序(进程)送到外存中,从而获得空闲内存空间来装入新程序(进程),或读人保存在外存中而处于就绪状态的程序。交换单位为整个进程的地址空间。交换技术常用于多道程序系统或小型分时系统中,因为这些系统大多采用分区存储管理方式。与分区式存储管理配合使用又称作“对换”或“滚进/滚出” (roll-in/roll-out)。

          原理:暂停执行内存中的进程,将整个进程的地址空间保存到外存的交换区中(换出swap out),而将外存中由阻塞变为就绪的进程的地址空间读入到内存中,并将该进程送到就绪队列(换入swap in)。

         交换技术优点之一是增加并发运行的程序数目,并给用户提供适当的响应时间;与覆盖技术相比交换技术另一个显著的优点是不影响程序结构。交换技术本身也存在着不足,例如:对换人和换出的控制增加处理器开销;程序整个地址空间都进行对换,没有考虑执行过程中地址访问的统计特性。

    3.7 覆盖与交换比较

           1)与覆盖技术相比,交换不要求程序员给出程序段之间的覆盖结构。

           2)交换主要是在进程与作业之间进行,而覆盖则主要在同一作业或进程内进行。 另外覆盖只能覆盖那些与覆盖程序段无关的程序段。

     

    四. 物理内存非连续:页式和段式存储管理


           在前面的几种存储管理方法中,为进程分配的空间是连续的,使用的地址都是物理地址。如果允许将一个进程分散到许多不连续的空间,就可以避免内存紧缩,减少碎片。基于这一思想,通过引入进程的逻辑地址,把进程地址空间与实际存储空间分离,增加存储管理的灵活性。地址空间和存储空间两个基本概念的定义如下:

    地址空间:将源程序经过编译后得到的目标程序,存在于它所限定的地址范围内,这个范围称为地址空间。地址空间是逻辑地址的集合。

    存储空间:指主存中一系列存储信息的物理单元的集合,这些单元的编号称为物理地址存储空间是物理地址的集合。

    根据分配时所采用的基本单位不同,可将离散分配的管理方式分为以下三种:
    页式存储管理、段式存储管理和段页式存储管理。其中段页式存储管理是前两种结合的产物。

    页式和段式管理区别

    页式和段式系统有许多相似之处。比如,两者都采用离散分配方式,且都通过地址映射机构来实现地址变换。但概念上两者也有很多区别,主要表现在:

          1)、需求:是信息的物理单位,分页是为了实现离散分配方式,以减少内存的碎片,提高内存的利用率。或者说,分页仅仅是由于系统管理的需要,而不是用户的需要。段是信息的逻辑单位,它含有一组其意义相对完整的信息。分段的目的是为了更好地满足用户的需要。

        一条指令或一个操作数可能会跨越两个页的分界处,而不会跨越两个段的分界处。

         2)、大小:页大小固定且由系统决定,把逻辑地址划分为页号和页内地址两部分,是由机器硬件实现的。段的长度不固定,且决定于用户所编写的程序,通常由编译系统在对源程序进行编译时根据信息的性质来划分。

         3)、逻辑地址表示:页式系统地址空间是一维的,即单一的线性地址空间,程序员只需利用一个标识符,即可表示一个地址。分段的作业地址空间是二维的,程序员在标识一个地址时,既需给出段名,又需给出段内地址。

         4)、比页大,因而段表比页表短,可以缩短查找时间,提高访问速度。

     

    五. 页式存储管理


    5.1 基本原理

            将程序的逻辑地址空间划分为固定大小的页(page),而物理内存划分为同样大小的页框(page frame)。程序加载时,可将任意一页放人内存中任意一个页框,这些页框不必连续,从而实现了离散分配。该方法需要CPU的硬件支持,来实现逻辑地址和物理地址之间的映射。在页式存储管理方式中地址结构由两部构成,前一部分是页号,后一部分为页内地址w(位移量),如图4所示:

          

          页式管理方式的优点是:

           1)没有外碎片,每个内碎片不超过页大比前面所讨论的几种管理方式的最大进步是,

           2)一个程序不必连续存放。

           3)便于改变程序占用空间的大小(主要指随着程序运行,动态生成的数据增多,所要求的地址空间相应增长)。

          缺点是:要求程序全部装入内存,没有足够的内存,程序就不能执行。

    5.2 页式管理的数据结构

             在页式系统中进程建立时,操作系统为进程中所有的页分配页框。当进程撤销时收回所有分配给它的页框。在程序的运行期间,如果允许进程动态地申请空间,操作系统还要为进程申请的空间分配物理页框。操作系统为了完成这些功能,必须记录系统内存中实际的页框使用情况。操作系统还要在进程切换时,正确地切换两个不同的进程地址空间到物理内存空间的映射。这就要求操作系统要记录每个进程页表的相关信息。为了完成上述的功能,—个页式系统中,一般要采用如下的数据结构。

            进程页表:完成逻辑页号(本进程的地址空间)到物理页面号(实际内存空间,也叫块号)的映射。
            每个进程有一个页表,描述该进程占用的物理页面及逻辑排列顺序,如图:

           

                                     图4-1 页表

            物理页面表:整个系统有一个物理页面表,描述物理内存空间的分配使用状况,其数据结构可采用位示图和空闲页链表

            对于位示图法,即如果该页面已被分配,则对应比特位置1,否置0.

           

                                      图4-2 页面表

            请求表:整个系统有一个请求表,描述系统内各个进程页表的位置和大小,用于地址转换也可以结合到各进程的PCB(进程控制块)里。如图:

          

                                           图4-3 请求表

    5.3 页式管理地址变换

           在页式系统中,指令所给出的地址分为两部分:逻辑页号和页内地址。

           原理:CPU中的内存管理单元(MMU)按逻辑页号通过查进程页表得到物理页框号,将物理页框号与页内地址相加形成物理地址(见图4-4)。

            逻辑页号,页内偏移地址->查进程页表,得物理页号->物理地址:

           

                                           图4-4 页式管理的地址变换

           上述过程通常由处理器的硬件直接完成,不需要软件参与。通常,操作系统只需在进程切换时,把进程页表的首地址装入处理器特定的寄存器中即可。一般来说,页表存储在主存之中。这样处理器每访问一个在内存中的操作数,就要访问两次内存:

           第一次用来查找页表将操作数的 逻辑地址变换为物理地址;

           第二次完成真正的读写操作。       

          这样做时间上耗费严重。为缩短查找时间,可以将页表从内存装入CPU内部的关联存储器(例如,快表) 中,实现按内容查找。此时的地址变换过程是:在CPU给出有效地址后,由地址变换机构自动将页号送人快表,并将此页号与快表中的所有页号进行比较,而且这 种比较是同时进行的。若其中有与此相匹配的页号,表示要访问的页的页表项在快表中。于是可直接读出该页所对应的物理页号,这样就无需访问内存中的页表。由于关联存储器的访问速度比内存的访问速度快得多。

     

     

    六. 段式存储管理


    6.1 基本原理

            在段式存储管理中,将程序的地址空间划分为若干个段(segment),这样每个进程有一个二维的地址空间。在前面所介绍的动态分区分配方式中,系统为整个进程分配一个连续的内存空间。而在段式存储管理系统中,则为每个段分配一个连续的分区,而进程中的各个段可以不连续地存放在内存的不同分区中。程序加载时,操作系统为所有段分配其所需内存,这些段不必连续,物理内存的管理采用动态分区的管理方法。

          在为某个段分配物理内存时,可以采用首先适配法、下次适配法、最佳适配法等方法。

          在回收某个段所占用的空间时,要注意将收回的空间与其相邻的空间合并。

          段式存储管理也需要硬件支持,实现逻辑地址到物理地址的映射。

          程序通过分段划分为多个模块,如代码段、数据段、共享段:

          –可以分别编写和编译

          –可以针对不同类型的段采取不同的保护

          –可以按段为单位来进行共享,包括通过动态链接进行代码共享

          这样做的优点是:可以分别编写和编译源程序的一个文件,并且可以针对不同类型的段采取不同的保护,也可以按段为单位来进行共享。

           总的来说,段式存储管理的优点是:没有内碎片,外碎片可以通过内存紧缩来消除;便于实现内存共享。缺点与页式存储管理的缺点相同,进程必须全部装入内存。

    6.2 段式管理的数据结构

             为了实现段式管理,操作系统需要如下的数据结构来实现进程的地址空间到物理内存空间的映射,并跟踪物理内存的使用情况,以便在装入新的段的时候,合理地分配内存空间。

           ·进程段表:描述组成进程地址空间的各段,可以是指向系统段表中表项的索引。每段有段基址(baseaddress),即段内地址。

            在系统中为每个进程建立一张段映射表,如图:

            

           ·系统段表:系统所有占用段(已经分配的段)。

          

           ·空闲段表:内存中所有空闲段,可以结合到系统段表中。

    6.3 段式管理的地址变换

                                 

                                                                      图4—5 段式管理的地址变换

            在段式 管理系统中,整个进程的地址空间是二维的,即其逻辑地址由段号和段内地址两部分组成。为了完成进程逻辑地址到物理地址的映射,处理器会查找内存中的段表,由段号得到段的首地址,加上段内地址,得到实际的物理地址(见图4—5)。这个过程也是由处理器的硬件直接完成的,操作系统只需在进程切换时,将进程段表的首地址装入处理器的特定寄存器当中。这个寄存器一般被称作段表地址寄存器。

     

    展开全文
  • 深入浅出内存管理-- 伙伴系统(buddy system)

    千次阅读 多人点赞 2018-12-17 18:57:39
    伙伴系统是内核中用来管理物理内存的一种算法,我们知道内存中有一些是被内核代码占用,还有一些是被特殊用途所保留,那么剩余的空闲内存都会交给内核内存管理系统来进行统一管理和分配, 内核中会把内存按照页来...
  • 计算机操作系统_内存管理

    千次阅读 2018-12-17 02:27:01
    内存管理 设计程序模拟内存的动态分区内存管理方法。内存空闲区使用空闲分区表进行管理,采用最先适应算法从空闲分区表中寻找空闲区进行分配,内存回收时不考虑与相邻空闲区的合并。 假定系统的内存共640K,初始...
  • 操作系统内存管理

    千次阅读 2017-04-20 11:08:11
    地址空间也可以这样理解,32位机上,创建进程时操作系统为进程分配4GB的独立地址空间,用户可以使用这4GB的独立地址空间。但是,反过来一想,给每个进程都分配4GB地址空间,对于8GB内存的计算机而
  • 操作系统实验——内存管理

    千次阅读 2017-11-10 18:56:25
    内存为什么要管理 在OS中,每个运行的进程都会占用内存,那么操作系统势必要做好两件事:内存分配和内存回收。这便是本次实验要做的模拟实验了。 内存分配策略 FF(首次适应算法) 这种策略旨在从最低地址的...
  • 操作系统——分页式内存管理

    万次阅读 多人点赞 2017-08-27 18:50:41
    操作系统——分页式内存管理为什么要引入内存管理?答:多道程序并发执行,共享的不仅仅只有处理器,还有内存,并发执行不过不进行内存管理,必将会导致内存中数据的混乱,以至于限制了进程的并发执行。扩充内存的两...
  • 2、操作系统内存管理——分页

    千次阅读 2017-08-12 17:34:05
    操作系统内存管理——分页
  • 操作系统内存管理

    万次阅读 2014-04-24 23:44:02
    Linux为了有效使用机器中的物理内存,在系统初始化阶段内存被划分成几个功能区域: 其中,Linux内核程序占据在物理内存的开始部分,接下来是供硬盘等块设备使用的高速缓冲区部分(其中要扣除显卡内存和ROM BIOS...
  • 操作系统内存管理——段页式(虚拟内存)
  • 操作系统——分段式内存管理

    千次阅读 2017-08-27 18:51:42
    操作系统——分段式内存管理分页式的优点从计算机的角度出发,提高了内存的利用率,提升了计算机的性能,以分页通过硬件机制实现,对用户透明分段式的优点考虑到用户和程序员,已满足方便编程、信息保护和共享、动态...
  • 操作系统内存管理内存空间的连续分配方式1.概述、分类内存空间的连续分配方式,是指为一个用户程序(作业)分配一个连续的内存空间。 按照内存空间划分方式的不同可将连续分配方式划分为以下四种方式: 1. 单一...
  • Android内存管理机制详解

    万次阅读 多人点赞 2012-12-13 10:37:33
    这是Linux内存管理的一个优秀特性,在这方面,区别于 Windows的内存管理。主要特点是,无论物理内存有多大,Linux都将其充份利用,将一些程序调用过的硬盘数据读入内存,利用内存读写的高速特性来提高Linux系统的...
  • 3.1.2 操作系统内存管理管些什么?

    千次阅读 多人点赞 2020-04-21 20:57:51
    内存空间的分配与回收2.内存空间的扩展(实现虚拟性)3.地址转换三种方式4.内存保护两种方式 0.思维导图 1.内存空间的分配与回收 2.内存空间的扩展(实现虚拟性) 3.地址转换 三种方式 4.内存保护 两种方式 ...
  • 深入理解linux内存管理之 页表管理

    万次阅读 2013-07-05 14:42:39
    页表是内存管理系统中的数据结构,用于向每个进程提供一致的虚拟地址空间,每个页表项保存的是虚拟地址到物理地址的映射以及一些管理标志。应用进程只能访问虚拟地址,内核必须借助页表和硬件把虚拟地址翻译为对物理...
  • 《计算机操作系统》总结三(内存管理

    千次阅读 多人点赞 2015-09-23 21:15:47
    内存管理 包括内存管理和虚拟内存管理内存管理包括内存管理概念、交换与覆盖、连续分配管理方式和非连续分配管理方式(分页管理方式、...内存管理(Memory Management)是操作系统设计中最重要和最复杂的内容之一。虽
  • 伙伴系统之伙伴系统概述--Linux内存管理(十五)

    万次阅读 多人点赞 2016-09-03 00:13:15
    日期 内核版本 架构 作者 GitHub CSDN 2016-09-02 Linux-4.7 ...1 前景回顾1.1 Linux内存管理的层次结构Linux把物理内存划分为三个层次来管理 层次 描述 存储节点(Node) CPU被划分为多个节点(no
  • 操作系统-内存管理-内存与外存的对换(swapping)1.对换的引入在多道程序环境下,可能会有如下两个问题: 内存中的某些进程可能被阻塞(由于等待I/O或其他原因),但是该进程占用了大量的内存空间,甚至会发生内存中...
  • 内存管理我的理解是分为两个部分,一个是物理内存的管理,另一个部分是物理内存地址到虚拟地址的转换。 物理内存管理 内核中实现了很多机制和算法来进行物理内存的管理,比如大名鼎鼎的伙伴系统,以及slab分配器等等...
  • 操作系统内存管理(概念)

    万次阅读 2016-05-30 14:06:31
    对于计算机系统而言,操作系统充当着基石的作用,它是连接计算机底层硬件与上层应用软件的桥梁,控制其他程序的运行,并且管理系统相关资源,同时提供配套的系统软件支持。对于专业的程序员而言,掌握一定的操作系统...
  • 在操作系统中,内存管理的目的是什么呢? 其中最主要的就是提高内存的利用率,所谓的提高内存利用率,就是尽可能的在内存中多存储进程,这就涉及到为进程分配内存空间了。分配的方式主要是有两种——连续分配和离散...
  • linux使用伙伴系统管理物理内存页。 一、伙伴系统原理 1. 伙伴关系 定义:由一个母实体分成的两个各方面属性一致的两个子实体,这两个子实体就处于伙伴关系。在操作系统分配内存的过程中,一个内存块常常被分成两...
  • 操作系统概论【四】- - 内存管理

    千次阅读 2020-09-06 17:23:58
    文章目录第四章、内存管理一、存储器的层次结构1. 局部性原理二、程序的链接和装入1. 程序的链接a.静态链接b.动态链接2. 程序的装入a.绝对装入方式b.可重定位装入方式(静态重定位)c.动态运行时装入(动态重定位)...
  • 计算存储的层次结构: 当前技术没有能够提供这样的存储器,因此大部分的计算机都有一个存储器层次结构,即少量的非常快速、昂贵、易变的... 内存管理主要包括虚地址、地址变换、内存分配和回收、内存扩充、内存共享
  • Linux内核子系统
  • Linux内存管理机制

    千次阅读 2017-02-16 04:07:24
    这是Linux内存管理的一个优秀特性,主要特点是,无论物理内存有多大,Linux 都将其充份利用,将一些程序调用过的硬盘数据读入内存(buffer/cache),利用内存读写的高速特性来提高Linux系统的数据访问性能。...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 1,206,030
精华内容 482,412
关键字:

内存管理系统