免费智能真题库 > 历年试卷 > 嵌入式系统设计师 > 2018年下半年 嵌入式系统设计师 上午试卷 综合知识
  第23题      
  知识点:   存储管理   页式存储管理   存储管理方案
  关键词:   32位   计算机系统   页式存储管理   存储管理        章/节:   嵌入式操作系统基础知识   嵌入式系统程序设计       

 
某计算机系统采用页式存储管理方案,假设其地址长度为32位,其中页号占20位,页内地址占12位。系统中页面总数与页面大小分别为(23) 。
 
 
  A.  1K, 1024K
 
  B.  4K, 1024K
 
  C.  1M, 1K
 
  D.  1M, 4K
 
 
 

 
  第51题    2019年下半年  
   67%
堆是一种有用的数据结构,下列关键字序列中,(51)是一个堆。
  第15题    2016年下半年  
   69%
结构化开发方法中,(15)主要包含对数据结构和算法的设计。
  第1题    2017年下半年  
   39%
在程序的执行过程中,Cache与主存的地址映射是由(1)完成的。
 
  第62题    2016年下半年  
   61%
以下C语言程序的输出结果是(62)。
  第63题    2011年下半年  
   68%
某处理器按照大端方式工作,以下C语言代码执行后的输出是(63)。
  第41题    2010年下半年  
   33%
执行下面的一段C程序后,变量x的值为(41)。
   知识点讲解    
   · 存储管理    · 页式存储管理    · 存储管理方案
 
       存储管理
        C程序中经常需要使用各种变量,如全局变量、静态变量、局部变量,编程时需要了解这些变量的作用域及其所占用的存储位置及存储空间大小,包括静态存储和动态存储的概念。若程序中的一个变量在运行时总是不正常地被改变,那么有理由怀疑它临近的数据存在溢出情况,从而改变了这个变量值。要进行跟踪排查,就必须知道该变量被分配的位置及其附近的其他变量。
        程序的编译单位是源程序文件,一个源文件可以包含一个或若干个函数。在函数内定义的变量是局部变量,而在函数之外定义的变量则称为外部变量,外部变量也就是通常所说的全局变量。
        例如,在下面的程序段中,有全局变量degree、cnt和局部变量times、price。
        
               内存布局
               一个C程序在不同的系统中运行时,虽然对其代码和数据所占用的内存空间会有不同的布局和安排,但是一般都包括正文段(包含代码和只读数据)、数据区、堆和栈等。例如,在Linux系统中进程的内存布局示意图如下图所示。
               
               程序的内存映像示意图
               (1)正文段中主要包括由CPU执行的机器指令,该存储区是只读区域,以防止程序由于意外事件而修改,该段也是可共享的,因此经常执行的程序在存储器中只需要有一个副本。
               (2)数据区(段)分为初始化部分和未初始化部分,在程序中已初始化的全局变量和静态局部变量的存储单元在该区域。还有程序中未初始化的全局数据所占存储区域,常称为BSS段(来源于早期汇编程序的一个操作,即Block Started by Symbol),在程序开始执行之前,内核将此段初始化为0。
               (3)栈是局部变量以及每次函数调用时所需保存的信息的存储区域,其空间的分配和释放由操作系统进行管理。每次函数调用时,其返回地址以及调用者的环境信息(例如某些寄存器)都存放在栈中。然后,在栈中为新被调用的函数的自动和临时变量分配存储空间。栈空间向低地址方向增长。
               (4)堆是一块动态存储区域,由程序员堆分配和释放,若程序员不释放,则程序结束时由操作系统回收。堆空间地址的增长方向是从低地址向高地址。在C程序中,通过调用标准库函数malloc/calloc/realloc等向系统动态地申请堆存储空间来存储相应规模的数据,之后用free函数释放所申请到的存储空间。
               当程序使用这些函数去获得新的内存空间时,系统首先在堆上进行内存空间的分配,操作系统一般需要维护一个记录空闲内存地址的链表。当系统收到程序的申请时,会遍历该链表,寻找适用于所申请空间大小的堆结点,然后将该结点从空闲结点链表中删除,并将该结点的空间分配给用户程序。另外,对于大多数系统,会在这块内存空间中的首地址处记录本次分配的大小,这样,代码中的free操作才能正确地释放本段内存空间。由于找到的堆结点大小不一定正好等于申请空间的大小,因此涉及到复杂的分配机制,需要进行系统调用,可能产生内存碎片以及用户态与核心态的转换等一系列问题。
               对于内存受限的系统,应尽量避免使用动态内存分配,多采用静态内存分配,从而在程序编译时就能确定其运行时所需要的存储空间。
               大端模式和小端模式
               在计算机系统中是以字节为单位存储信息的,每个地址单元都对应着一个字节(8bit)。但是在C程序中除了8bit的char型数据外,还有16bit的short型、32bit的int型及long型(要看具体的编译器)。另外,对于16位或者32位的处理器,由于寄存器宽度为多个字节,那么必然存在着如何将多个字节安排的问题。因此就导致了大端(Big-endian)存储模式和小端(Little-endian)存储模式。
               大端模式就是高位字节存储在内存的低地址端,低位字节存储在内存的高地址端。
               小端模式就是低位字节存储在内存的低地址端,高位字节存储在内存的高地址端。
               常用CPU中的PowerPC、IBM、Sun、KEIL C51采用大端模式,X86、DEC采用小端模式,很多ARM、DSP为小端模式。有些ARM处理器还可以由硬件来选择是大端模式还是小端模式。
               一般操作系统是小端模式,而通信协议是大端模式。另外,Java和所有的网络通信协议都是使用大端模式的编码。
               例如,对于一个32bit的十六进制整数0x12345678,在Little-endian模式以及Big-endian模式内存中的存储方式(假设从地址0x4000开始存放)如下表所示。
               
               大端模式和小端模式存储示例
 
       页式存储管理
               基本原理
               分区存储管理的一个特点是连续性,每个程序都分得一片连续的内存区域。这种连续性将导致碎片问题,包括固定分区中的内碎片和可变分区中的外碎片。为了解决这些问题,人们又提出了页式存储管理方案。它的基本出发点是打破存储分配的连续性,使一个程序的逻辑地址空间可以分布在若干个离散的内存块上,从而达到充分利用内存,提高内存利用率的目的。
               页式存储管理的基本思路是:一方面,把物理内存划分为许多个固定大小的内存块,称为物理页面(physical page),或页框(page frame)。另一方面,把逻辑地址空间也划分为大小相同的块,称为逻辑页面(logical page),或简称为页面(page)。页面的大小要求是2n,一般在512B到8KB之间。当一个用户程序被装入内存时,不是以整个程序为单位,把它存放在一整块连续的区域,而是以页面为单位来进行分配。对于一个大小为N个页面的程序,需要有N个空闲的物理页面把它装进来,当然,这些物理页面不一定是连续的。
               下图是一个具体的例子。各个任务的逻辑地址空间和内存的物理地址空间被划分为1KB大小的页面。任务1有两个页面,任务2有三个页面,任务3有一个页面。当这三个任务被装入内存后,它们在内存空间的分布可能是:任务1的两个页面分别存放在第5和第6个物理页面中,它们碰巧被放在了一起。任务2的三个页面分别存放在第2、第4和第7个物理页面中。也就是说,虽然它们在逻辑地址空间是三个连续的页面,但在物理地址空间却被分散在内存的不同位置。最后,任务3的这个页面被存放在第8个物理页面中。
               
               页式存储管理的一个例子
               在实现页式存储管理的时候,需要解决以下的几个问题:
               .数据结构:用于存储管理的数据结构是什么?
               .内存的分配与回收:当一个任务到来时,如何给它分配内存空间?当一个任务运行结束后,如何回收它所占用的内存空间?
               .地址映射:当一个任务被加载到内存后,可能被分散地存放在若干个不连续的物理页面当中。在这种情形下,如何把程序中使用的逻辑地址转换为内存访问时的物理地址,以确保它能正确地运行。
               数据结构
               在页式存储管理中,最主要的数据结构有两个。
               .页表:页表给出了任务的逻辑页面号与内存中的物理页面号之间的对应关系。
               .物理页面表:用来描述内存空间中各个物理页面的使用分配状况。在具体实现上,可以采用位示图或空闲页面链表等方法。
               下图是页表的一个例子。在任务的逻辑地址空间当中,总共有4个页面,即页面0、页面1、页面2和页面3。页表描述的是逻辑页面号与物理页面号之间的对应关系,即每一个逻辑页面存放在哪一个物理页面中。页表的下标是逻辑页面号,从0到3。相应的页表项存放的就是该逻辑页面所对应的物理页面号。在本例中,任务的4个逻辑页面分别存放在第1、第4、第3和第7个物理页面中。
               
               页表示例
               内存的分配与回收
               当一个任务到来时,需要给它分配相应的内存空间,即将其每一个逻辑页面都装入到内存当中。显然,内存的分配与回收算法与物理页面表的实现方法是密切相关的。以位示图为例,内存的分配过程是这样的:
               (1)对于一个新来的任务,计算它所需要的页面数N。然后查看位示图,看是否还有N个空闲的物理页面。
               (2)如果有足够的空闲物理页面,就去申请一个页表,其长度为N,并把页表的起始地址填入到该任务的任务控制块TCB当中。
               (3)分配N个空闲的物理页面,把它们的编号填入到页表中。这样,就建立了逻辑页面与物理页面之间的对应关系。
               (4)修改位示图,对刚刚被占用的那些物理页面进行标记。
               当一个任务运行结束,释放了它所占用的内存空间后,需要对这些物理页面进行回收,并对位示图的内容进行相应的修改。
               地址映射
               如前所述,当一个任务被加载到内存后,它的各个连续的逻辑页面,被分散地存放在若干个不连续的物理页面当中。在这种情形下,为了保证程序能够正确地运行,需要把程序中使用的逻辑地址转换为内存访问时的物理地址,也就是地址映射。
               那么如何将一个逻辑地址映射为相应的物理地址呢?在页式存储管理当中,连续的逻辑地址空间被划分为一个个的逻辑页面,这些逻辑页面被装入到不同的物理页面当中。也就是说,系统是以页面为单位来进行处理的,而不是以一个个的字节为单位。因此,地址映射的基本思路是:
               .逻辑地址分析:对于给定的一个逻辑地址,找到它所在的逻辑页面,以及它在页面内的偏移地址;
               .页表查找:根据逻辑页面号,从页表中找到它所对应的物理页面号;
               .物理地址合成:根据物理页面号及页内偏移地址,确定最终的物理地址。
                      逻辑地址分析
                      由于页面的大小一般都是2的整数次幂,因此,人们可以很方便地进行逻辑地址的分析。具体来说,对于给定的一个逻辑地址,可以直接把它的高位部分作为逻辑页面号,把它的低位部分作为页内偏移地址。例如,假设页面的大小是4KB,即212,逻辑地址为32位。那么在一个逻辑地址当中,最低的12位就是页内偏移地址,而剩下的20位就是逻辑页面号。
                      下图是逻辑地址分析的一个例子,在这个例子中,逻辑地址用十六进制形式表示。假设页面的大小为1KB,逻辑地址为0x3BAD。在这种情形下,首先把这个十六进制的地址展开为二进制的形式。然后,由于页面的大小为1KB,即2的10次方,所以这个逻辑地址的最低10位,就表示页内偏移地址,而剩下的最高6位,就表示逻辑页面号。因此,该地址的逻辑页面号是0x0E,页内偏移地址是0x03AD。
                      
                      逻辑地址分析的例子
                      如果逻辑地址不是用十六进制,而是用十进制的形式来表示,那么有两种做法:一是先把它转换为十六进制的形式,然后重复刚才的步骤。二是采用如下的计算方法:
                      逻辑页面号=逻辑地址/页面大小
                      页内偏移量=逻辑地址%页面大小
                      用页面大小去除逻辑地址,得到的商就是逻辑页面号;得到的余数就是页内偏移地址。例如,假设页面的大小为2KB,现在要计算逻辑地址7145的逻辑页面号和页内偏移地址。用2048去除7145,得到的商是3,余数是1001。所以这个逻辑地址的逻辑页面号是3,页内偏移地址是1001。实际上,这个算法和刚才的十六进制的方法是完全等价的。从二进制运算的角度来看,一个是右移操作,一个是除法操作。把一个整数右移N位等价于把它除以2N
                      页表查找
                      对于给定的一个逻辑地址,如果知道其逻辑页面号,就可以去查找页表,从中找到相应的物理页面号。
                      在具体实现上,页表通常是保存在内核的地址空间中,因为它是操作系统的一个数据结构。另外,为了能够访问页表的内容,在硬件上要增加一对寄存器。一个是页表基地址寄存器,用来指向页表的起始地址;另一个是页表长度寄存器,用来指示页表的大小,即对于当前任务,它总共包含有多少个页面。操作系统在进行任务切换的时候,会去更新这两个寄存器当中的内容。
                      物理地址合成
                      对于给定的一个逻辑地址,如果已经知道了它所对应的物理页面号和页内偏移地址,可以采用简单的叠加算法,计算出最终的物理地址。假设物理页面号为f,页内偏移地址为offset,每个页面的大小为2n,那么相应的物理地址为:f×2n+offset。
                      下图是页式存储管理当中的地址映射机制,也是以上各个步骤的一个综合。假设在程序的运行过程中,需要去访问某个内存单元,因此就给出了这个内存单元的逻辑地址。如前所述,这个逻辑地址由两部分组成,一是逻辑页面号,二是页内偏移地址。这个分析工作是由硬件自动来完成的,对用户是透明的。在页表基地址寄存器当中,存放的是当前任务的页表首地址。将这个首地址与逻辑页面号相加,就找到相应的页表项。里面存放的是这个逻辑页面所对应的物理页面号。将这个物理页面号取出来,与页内偏移地址进行组合,从而得到最终的物理地址。然后就可以用这个物理地址去访问内存。
                      
                      页式存储管理中的地址映射
                      现有的这种地址映射方案,虽然能够实现从逻辑地址到物理地址的转换,但它有一个很大的问题。当程序运行时需要去访问某个内存单元,例如,去读写内存当中的一个数据,或是去内存取一条指令,需要访问2次内存。第一次是去访问页表,取出物理页面号;第二次才是真正去访问数据或指令。也就是说,内存的访问效率只有50%。这样,就会降低获取数据的存取速度,进而影响到整个系统的使用效率。为了解决这个问题,人们又引入了快表的概念。它的基本思路来源于对程序运行过程的一个观察结果。对于绝大多数的程序,它们在运行时倾向于集中地访问一小部分的页面。因此,对于它们的页表来说,在一定时间内,只有一小部分的页表项会被经常地访问,而其他的页表项则很少使用。根据这个观察结果,人们在MMU中增加了一种特殊的快速查找硬件:TLB(Translation Lookaside Buffer),或者叫关联存储器,用来存放那些最常用的页表项。这种硬件设备能够把逻辑页面号直接映射为相应的物理页面号,不需要再去访问内存当中的页表,这样就缩短了页表的查找时间。
                      在TLB方式下,地址映射的过程略有不同。当一个逻辑地址到来时,它首先会到TLB当中去查找,看这个逻辑页面号所在的页表项是否包含在TLB当中,这个查找的速度是非常快的,因为它是以并行的方式进行。如果能够找到的话,就直接从TLB中把相应的物理页面号取出来,与页内偏移地址拼接成最终的物理地址。如果在TLB中没有找到该逻辑页面,那只能采用通常的地址映射方法,去访问内存当中的页表。接下来,硬件还会在TLB当中寻找一个空闲单元,如果没有空闲单元,就把某一个页表项驱逐出来,然后把刚刚访问过的这个页表项添加到TLB当中。这样,如果下次再来访问这个页面,就可以在TLB中找到它。
                      页式存储管理方案的优点是:
                      (1)没有外碎片,而且内碎片的大小不会超过页面的大小。这是因为系统是以页面来作为内存分配的基本单位,每一个页面都能够用上,不会浪费。只是在任务的某一些页面当中,可能没有装满,里面有一些内碎片。
                      (2)程序不必连续存放,它可以分散地存放在内存的不同位置,从而提高了内存利用率。
                      (3)便于管理。
                      页式存储管理方案的缺点主要有:
                      (1)程序必须全部装入内存,才能够运行。如果一个程序的规模大于当前的空闲空间的总和,那么它就无法运行。
                      (2)操作系统必须为每一个任务都维护一张页表,开销比较大。简单的页表结构已经不能满足要求,必须设计出更为复杂的结构,如多级页表结构、哈希页表结构、反置页表等。
 
       存储管理方案
        存储管理的主要目的是解决多个用户使用主存的问题,其存储管理方案主要包括分区存储管理、分页存储管理、分段存储管理、段页式存储管理及虚拟存储管理。
               固定分区
               固定分区是一种静态分区方式,在系统生成时已将主存分成若干个分区,每个分区的大小可以不等,但分区大小固定不变,每个分区装一个且只能装一个作业。操作系统通过主存分配情况表管理主存。
               固定分区的缺点是已分配区中存在未用空间,原因是程序或作业的大小不可能刚好等于分区的大小,故造成了空间的浪费。通常将已分配分区内的未用空间叫做零头或内碎片。
               可变分区
               可变分区是一种动态分区方式,存储空间的划分是在作业装入时进行的,故分区的个数是可以变的,分区的大小刚好等于作业的大小。
               引入可变分区方法,使主存分配有较大的灵活性,也提高了主存的利用率。但是可变分区会引起碎片的产生。解决碎片的方法是拼接(或称紧凑),即向一个方向(如向低地址端)移动已分配的作业,使那些零散的小空闲区在另一方向连成一片。分区的拼接技术一方面要求能够对作业进行重定位,另一方面系统在拼接时要耗费较多的时间。
               系统利用空闲分区表来管理主存中的空闲分区,请求和释放分区可以采用最佳适应算法、最差适应算法、首次适应算法和循环首次适应算法4种分配策略进行主存分配。
               (1)最佳适应算法。假设系统中有X1X2X3,…,Xi,…,Xn个空闲区(自由区),每当用户申请一个空间时,将从这n个空闲区中找到一个最接近用户需求的分区。这种算法能保留较大的空白区。但缺点是空闲区不可能刚好等于用户要求的区,所以必然要将一个分区一分为二。随着系统不断地分配和释放空间,可能会使产生的小分区小到无法再继续分配,这样的无用小分区称为外碎片。
               (2)最差适应算法。接到主存申请时,系统总是将用户作业装入最大的空闲区。这种算法将一个最大的分区一分为二,所以剩下的空闲区通常也较大,不容易产生外碎片。
               (3)首次适应算法。每当用户作业申请一个空间时,系统总是从主存的低地址开始选择一个能装入作业的空白区。当用户释放空间时,该算法更易实现相邻的空白区合并。
               (4)循环首次适应算法。与首次适应算法的不同之处是,每次分配都是从刚分配的空闲区开始寻找一个能满足用户要求的空闲区。
               可重定位分区
               可重定位分区是解决碎片问题的简单而又行之有效的方法。其基本思想是移动所有已分配好的分区,使之成为连续区域。由于移动分区是要付出代价的,所以通常是在用户请求空间得不到满足时进行。移动已分配的分区会导致地址发生变化,所以会产生地址重定位的问题。
               分区保护的目的是防止未经核准的用户访问分区,常用以下两种保护方式。
               (1)上界/下界寄存器。采用上界/下界寄存器保护法时,上界寄存器中存放的是作业的装入地址,下界寄存器中存放的是作业的结束地址,形成的物理地址必须满足
               上界寄存器≤物理地址≤下界寄存器
               (2)基址寄存器和限长寄存器。基址寄存器用来存放用户程序在主存的起始地址,限长寄存器用来存放用户程序的长度,形成的物理地址必须满足
               基址寄存器≤物理地址≤基址寄存器+限长寄存器
   题号导航      2018年下半年 嵌入式系统设计师 上午试卷 综合知识   本试卷我的完整做题情况  
1 /
2 /
3 /
4 /
5 /
6 /
7 /
8 /
9 /
10 /
11 /
12 /
13 /
14 /
15 /
 
16 /
17 /
18 /
19 /
20 /
21 /
22 /
23 /
24 /
25 /
26 /
27 /
28 /
29 /
30 /
 
31 /
32 /
33 /
34 /
35 /
36 /
37 /
38 /
39 /
40 /
41 /
42 /
43 /
44 /
45 /
 
46 /
47 /
48 /
49 /
50 /
51 /
52 /
53 /
54 /
55 /
56 /
57 /
58 /
59 /
60 /
 
61 /
62 /
63 /
64 /
65 /
66 /
67 /
68 /
69 /
70 /
71 /
72 /
73 /
74 /
75 /
 
第23题    在手机中做本题