【简记】Operating System—— memory management(分页,分段,页表大小计算)

来源:互联网 发布:网络热点视频 编辑:程序博客网 时间:2024/04/30 14:31

This memo is based on the course of Dr.Li with Operating System as the reference book.

本章内容:

  • 页式内存管理(非连续)
  • TLB(类似网络中DNS服务器的作用)
  • 页表的结构(层次结构,哈希结构,反向结构)
  • 分段

8.4 分页

分页( paging) 内存管理方案允许进程的物理地址空间可以是非连续的。

8.4.1 基本方法

实现分页的基本方法涉及将物理内存分为固定大小的块,称为帧(frame); 而将逻辑地址也分为同样大小的块,称页(page)。

页大小是由硬件来决定的。页的大小通常为2的幂。同时逻辑地址也是2的幂。所以在求页号和偏移的时候可以用左移右移操作,加快速度。

由CPU 生成的每个地址分为两个部分:页号(p) 和页偏移(d) 。页号作为页表的索引。页表包含每页所在物理内存的基地址,这些基地址与页偏移的组合就形成了物理地址,就可送交物理单元。

由于页大小和帧大小相同,下图中的d也相同,这样在转换中只需要求得对应物理内存中的基值起点,再加上偏移d即可,转换更加方便。

这里写图片描述

这里写图片描述

采用分页技术不会产生外部碎片(因为进程得到的空间是以页为单位),所以可能会有内部碎片。

帧表( frametable ) 中,每个条目对应着一个帧,以表示该帧是空闲还是己占用, 如果占用,是被哪个进程的哪个页所占用。


8.4.2 硬件支持

由于页表有可能非常大,所以需要将页表放在内存中,并将页表基寄存器( page-table base register ) 指向页表。

转换表缓冲区( translation look -aside buffer, TLB)。TLB 是关联的快速内存。

TLB 与页表一起按如下方法使用:TLB 只包括页表中的一小部分条目。当CPU 产生逻辑地址后,其页号提交给TLB 。如果找到页号,那么也就得到了帧号,并可用来访问内存。整个任务与不采用内存映射相比,其时间增加不会超过10%。

如果页码不在TLB中(称为TLB 失效),那么就需要访问页表。当得到帧号后, 就可以用它采访问内存( 如图8. 11所示)。同时,将页号和帧号增加到TLB 中,这样下次再用时就可很快查找到。如果TLB 中的条目已满,那么操作系统会选择一个来替换。替换策略有很多, 从最近最少使用替换(LRU ) 到随机替换等。另外,有的TLB允许有些条目固定下来,也就是说它们不会从TLB中被替换。通常内核代码的条目是固定下来的。

这里写图片描述

===
8.4.3 保护

在分页环境下, 内存保护是通过与每个帧相关联的保护位来实现的。如:

  • 可以用一个位来定义一个页是可读写还是只读的。
  • 还有一个位通常与页表中的每一条目相关联: 有效-无效位。
    这里写图片描述

===
8.4.4 共享页

分页的优点之一在于可以共享公共代码,这种考虑对分时环境特别重要。

如果代码是可重入代码( reentrant code,或称为纯代码),则可以共享。


8.5 页表结构
本节将讨论一些组织页表的常用技术。

8.5.1 层次页表

一个系统中的页表存储的条目可能有上百万条,将页表划分为更小部分,便于存储。

一个逻辑地址被分为20 位的页码和12 位的页偏移。因为要对页表进行再分页,所以该页号(20)可分为10 位的页码和10 位的页偏移。

由于地址转换由外向内,这种方案也称为向前映射页表 。
注意最后的一个方块,已经指向了具体物理内存。(但是在实现上还是通过计算对应的物理地址,经过总线寻址才能拿到具体数据)
这里写图片描述

===
8.5.2 哈希页表

处理超过32位地址空间的常用方法是使用哈希页表(64位系统上)。

每个元素有3 个域: ( 1 )虚拟页码 (2)所映射的帧号(3)指向链表中下一个元素的指针。

这里写图片描述

===
8.5.3 反向页表

通常,每个进程都有一个相关页表。页表是按虚拟地址排序的,操作系统能够计算出所对应条目在页表中的位置,并可以直接使用该值。
这种方法的缺点之一是每个页表可能有很多项。这些表可能消耗大量物理内存,却仅用来跟踪物理内存是如何使用的。

为了解决这个问题,可以使用反向页表。反向页表对于每个真正的内存页或帧才有一个条目。

系统的每个虚拟地址有一个三元组< process- id, page-nurmber, offset >;
每个反向页表的条目为一对< process-id, page-number > , 其中process-id 用来作为地址空间的标识符。当需要内存引用时,由< process-id, page-number >组成的虚拟地址部分送交内存子系统。通过查找反向页表来寻找匹配。如果匹配找到,例如条目i,那么就产生了物理地址< i, offset > 。如果没有匹配,那么就是试图进行非法地址访问。

这里写图片描述


分页和分段系统有许多相似之处,但在概念上两者完全不同,主要表现在:
1、页是信息的物理单位,分页是为实现离散分配方式,以消减内存的外零头,提高内存的利用率;或者说,分页仅仅是由于系统管理的需要,而不是用户的需要,对用户是不可见的。
段是信息的逻辑单位,它含有一组意义相对完整的信息。分段的目的是为了能更好的满足用户的需要。
2、页的大小固定且由系统确定,把逻辑地址划分为页号和页内地址两部分,是由机器硬件实现的,因而一个系统只能有一种大小的页面。
段的长度却不固定,决定于用户所编写的程序,通常由编辑程序在对源程序进行编辑时,根据信息的性质来划分。
3、分页的作业地址空间是维一的,即单一的线性空间,程序员只须利用一个记忆符,即可表示一地址。
分段的作业地址空间是二维的,程序员在标识一个地址时,既需给出段名,又需给出段内地址。


8.6 分段

分段(segmentation)就是支持这种用户视角的内存管理方案。

段是编号的,是通过段号而不是段名来引用的。因此,逻辑地址由有序对组成< segment-number, offset >

一个C 编译器可能会创建如下段:
①代码
②全局变量
③堆(内存从堆上分配)
④每个线程采用的栈
⑤标准的C 库函数

http://blog.csdn.net/cc_net/article/details/24726287


一个页的大小为何为4K

这里写图片描述

一种计算方法是,因为32位下,最低的12位是存放页偏移,所以可能的偏移一共有2^12次方,内存中基本的存储单位是1B,所以对应一个帧表的大小是4KB,页表也是4KB


前提:32位逻辑地址空间的计算机系统,两级页表,每个页中每个条目占4Byte,即32位的数据

设:页大小为X(byte)

则:X/4就是每个页中可以存取的条目个数

两级页表的地址转化关系如图8.1所示

假设在一个32位的条目中存放此内存的地址,则2*log2(X/4)就是图1中,p1+p2的位数。

2^(p1+p2):系统可以寻址多少个页面

(x/4)^2:前两级页表共可以选择多少个entry,因为第一级页表entry个数是x/4,第二级相同,所以相乘既共有多少个entry

系统可以寻址的页面数目=前两级页表共可以选择多少个entry,即2^(p1+p2)=(x/4)^2====>2*log2(X/4)=p1+p2。

此外:如果页大小为X,那么为了偏移量能够寻址所有的X位,需要:2的d次方=X,即log2(X)=d。

然而由图一知,p1+p2+d=32,所以:

2*log2(X/4)+log2(X)=32

可以计算得到X=4096.即页的大小为4096bit=4k。

以上只是硬件在最充分利用资源情况下的方式,有人说为什么其他大小的页面(如8k)不行?不是不行,是这么做就是傻,为什么?解释如下:

前提如上面所述,如果页面大小是8k,d就必须等于13(2^13=8k),p1+p2=19;

此时每个entry还是4B,则每个页面共有entry=8K/4B=2048个;

假设用p2寻址2048个entry,则p2=11,此时p1=8;

问题来了,p1=8,则第一级页表只能寻址2^8=256个entry,此时第一级页表就有2048-256=1792个entry不能使用,这是多大的资源浪费???!!!

当然,系统其他地方的开销是需要平衡的,所以4k是一个综合评价后的结果。

但是,以后的大型系统,内存很可能上升到T级别,到那时在用4k页就是傻。目前ARMv8 64位的Linux中,大内存情况下2M页是比较合理的,而且OS中对其支持很完美。

阅读全文
0 0
原创粉丝点击