Linux 内存管理简介

1.       存储层次

      高速缓存(cache)    --〉   主存(main memory)      ---〉     磁盘(disk)

   理解存储层次结构的根源:CPU速度和存储器速度的差距。

   层次结构可行的原因:局部性原理。

   LINUX的任务:

l         减小footprint,提高cache命中率,充分利用局部性。

l         实现虚拟存储以满足进程的需求,有效地管理内存分配,力求最合理地利用有限的资源。

2.       MMU的作用

辅助操作系统进行内存管理,提供虚实地址转换等硬件支持。没有它,操作系统不能够真正实现进程空间的隔离,也就不能实现真正的多任务。比如uClinux,去掉了MMU相关的代码,所以在创建进程时只有vfork,而没有fork。

3.       x86的地址

逻辑地址: 出现在机器指令中,用来制定操作数的地址。段:偏移

线性地址:逻辑地址经过分段单元处理后得到线性地址,这是一个32位的无符号整数,可用于定位4G个存储单元。

物理地址:线性地址经过页表查找后得出物理地址,这个地址将被送到地址总线上指示所要访问的物理内存单元。

   

4.       x86的段

保护模式下的段:选择子+描述符。不仅仅是一个基地址的原因是为了提供更多的信息:保护、长度限制、类型等。描述符存放在一张表中(GDT或LDT),选择子可以认为是表的索引。段寄存器中存放的是选择子,在段寄存器装入的同时,描述符中的数据被装入一个不可见的寄存器以便cpu快速访问。

   专用寄存器:GDTR(包含全局描述附表的首地址),LDTR(当前进程的段描述附表首地址),TSR(指向当前进程的任务状态段)

 

LINUX使用的段:

    __KERNEL_CS: 内核代码段。范围 0-4G。可读、执行。DPL=0。

    __KERNEL_DS:内核代码段。范围 0-4G。可读、写。DPL=0。

    __USER_CS:内核代码段。范围 0-4G。可读、执行。DPL=3。

    __USER_DS:内核代码段。范围 0-4G。可读、写。DPL=3。

    TSS(任务状态段):存储进程的硬件上下文,进程切换时使用。(因为x86硬件对TSS有一定支持,所有有这个特殊的段和相应的专用寄存器)。但Linux并不使用这个Intel规定的机制进行进程切换。后面讲进程管理时会看到这点。

   

__USER_CS和__USER_DS段都是被所有在用户态下的进程共享的。注意不要把这个共享和进程空间的共享混淆:虽然大家使用同一个段,但通过使用不同的页表由分页机制保证了进程空间仍然是独立的。

 

段功能是Intel定义的,在X86系列处理器上必须使用。为了保持其处理器的前后兼容性,Intel保留了段机制。在386之后,又有段又有页,在保护机制上这是重复了,从而影响了存储器访问的性能。Linux很巧妙地将段功能的影响降到了最低。如通过使用基址为0的段,使逻辑地址==线性地址。也即是所有的进程都使用的是相同的线性地址空间0x00000000-0xC0000000.

 

5.       x86的分页机制

与段式存储管理线笔,页式存储管理有很多好处。首先,页面都是固定大小的,便于管理。更重要的是,但要将一部分物理空间的内容换乘到磁盘上的时候,在段式存储管理中要将整个段都换出,而段通常都很大,效率上页式存储管理要高很多。

x86硬件支持两级页表,奔腾pro以上的型号还支持Physical address Extension Mode和三级页表。所谓的硬件支持包括一些特殊寄存器(cr0-cr4)、以及CPU能够识别页表项中的一些标志位并根据访问情况做出反应等等。如读写Present位为0的页或者写Read/Write位为0的页将引起CPU发出page fault异常,访问完页面后自动设置accessed位等。

 

linux采用的是一个体系结构无关的三级页表模型(如图),使用一系列的宏来掩盖各种平台的细节。例如,通过把PMD看作只有一项的表并存储在pgd表项中(通常pgd表项中存放的应该是pmd表的首地址),页表的中间目录(pmd)被巧妙地‘折叠’到页表的全局目录(pgd),从而适应了二级页表硬件。

 

6.         Linux下进程虚地址空间

目前,在x86系列处理器上,Linux进程虚地址为32位线性地址。32位地址意味着4G字节的虚地址空间,Linux内核将这4G的地址空间分成了两部分。最高1G字节(0xC0000000-0xFFFFFFFF)用于内核本身,即系统空间。而低3G字节空间(0x00000000-0xBFFFFFFF)用于各进程的用户空间。这样,理论上每个进程可以使用的用户空间都是3G字节。当然,实际的空间大小受到物理存储器大小的限制。系统空间是由各个进程所共享了,每当一个进程因某种原因(系统调用或时钟中断等)进入了内核,该进程就在共享的系统空间中运行,也即是使用的地址可以是(0x00000000-0xFFFFFFFF)。而在用户空间运行的时候,则只能是低3G的地址空间。

 

7.       TLB

TLB全称是Translation Look-aside Buffer,用来加速页表查找。这里关键的一点是:如果操作系统更改了页表内容,它必须相应的刷新TLB以使CPU不误用过时的表项。

 

8.       Cache

Cache 基本上是对程序员透明的,但是不同的使用方法可以导致大不相同的性能。linux有许多关键的地方对代码做了精心优化,其中很多就是为了减少对cache不必要的污染。如把只有出错情况下用到的代码放到.fixup section,把频繁同时使用的数据集中到一个cache行(如struct task_struct),减少一些函数的footprint。

这里要说明一下,.fixup section,一种尽量使程序回到正常运行的机制,是GCC编译器提供的。Linux内核也是一个程序,所以也会有可能崩溃的时候,所以这里采用了一定保护措施,使内核能够回到之前的某个正常的点上。

 

 

 

9.       Linux物理页面管理

内核维护着一个page结构数组mem_map,系统在初始化时根据物理内存的大小建立这个数组,作为物理页面的仓库,每一个数组元素都代表一个物理页面。

 

 

 

 

 

 

 

 

 

 

 

 


Linux使用了Buddy关系系统来维护物理页面的使用。

 

 

10.   slab方法

Linux借鉴了Solaris的经验,设计了一种有效的管理内核数据结构的机制slab。每个slab即是一个对象容器,可以容纳若干同种对象的块。内核需要某种数据结构是就会在这里面找,效率很高。比如进程PCB task_struct结构、文件系统的inode结构。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值