linux虚拟内存子系统简介

MMU(内存管理单元)

负责将虚拟地址转换为物理地址,数据存放在主存上,cpu访存时至少需要两次,第一次获取物理地址;第二次才获取数据。

    TLB:为了改善虚拟地址到物理地址的转换速度,提高cpu访存速度。

       原理:TLB利用的是页表的访问局部性,即当一个转换的虚拟页号被使用时,它可能在不久

         的将来再次被使用到。TLB是一种高速缓存,当cpu访问第一次某个线性地址时,通

         过计算获得对应的物理地址,同时,该线性地址和物理地址的对应关系保存在一个

         TLB表项中,以后对同一线性地址的访问,直接从TLB表项中获取物理地址即可。

      TLB内部存放的基本是页表条目,对应着RAM中存放的页表条目。页表条目的大小固定不变

      的,所以TLB容量越大,所能存放的页表条目越多,TLB 的命中率也越大。这是内存优化可

      以考虑的一个点



buddy allocator(伙伴系统):是一种动态内存分配方式,内存中有多个分区,规定每个分区都是2^n(n可不同),为相同大小的空闲分区设立一个空闲分区双向链表,即每个链表中空闲分区n都相同。分配时,首先计算n值,根据n值在对应大小为2^n的空闲分区链表中查找,如果找到即分配,找不到则将其向上扩在2^(n+1)链表中查找,把一个大小为2^(n+1)d的空闲分区分成两个相等的部分,这两个大小相等的分区就称为伙伴,其中一个用于分配,另一个加入2^i的空闲分区链表。回收时,如果伙伴是空闲的,则会合并成更大的空闲分区,加入到更大的链表中。


slab allocator

    一些需要频繁使用的同样大小数据经常在使用后不久又再次被用到,而这些内核对这些数据内存的分配和初始化的时间可能远远超过使用和释放内存的时间,所以首先从操作系统申请一大块内存,并将其分割成各种尺寸的块Chunk,并把尺寸相同的块分成组Slab Class。将内存对象使用过后使用slab保存起来,以备将来再次使用。

图 1 给出了 slab 结构的高层组织结构。在最高层是 cache_chain,这是一个 slab 缓存的链接列表。这对于 best-fit 算法非常有用,可以用来查找最适合所需要的分配大小的缓存(遍历列表)。cache_chain 的每个元素都是一个 kmem_cache 结构的引用(称为一个 cache)。它定义了一个要管理的给定大小的对象池。

图 1. slab 分配器的主要结构

linux虚拟内存子系统简介

每个缓存都包含了一个 slabs 列表,这是一段连续的内存块(通常都是页面)。存在 3 种 slab:

  • slabs_full

  • 完全分配的 slab

  • slabs_partial

  • 部分分配的 slab

  • slabs_empty

  • 空 slab,或者没有对象被分配

注意 slabs_empty 列表中的 slab 是进行回收(reaping)的主要备选对象。正是通过此过程,slab 所使用的内存被返回给操作系统供其他用户使用。

slab 列表中的每个 slab 都是一个连续的内存块(一个或多个连续页),它们被划分成一个个对象。这些对象是从特定缓存中进行分配和释放的基本元素。注意 slab 是 slab 分配器进行操作的最小分配单位,因此如果需要对 slab 进行扩展,这也就是所扩展的最小值。通常来说,每个 slab 被分配为多个对象。

由于对象是从 slab 中进行分配和释放的,因此单个 slab 可以在 slab 列表之间进行移动。例如,当一个 slab 中的所有对象都被使用完时,就从slabs_partial 列表中移动到 slabs_full 列表中。当一个 slab 完全被分配并且有对象被释放后,就从 slabs_full 列表中移动到slabs_partial 列表中。当所有对象都被释放之后,就从 slabs_partial 列表移动到 slabs_empty 列表中。


脏页

因为硬盘的读写速度远赶不上内存的速度,系统就把读写比较频繁的数据事先放到内存中,以提高读写速度,这就叫高速缓存,linux是以页作为高速缓存的单位,当进程修改了高速缓存里的数据时,该页就被内核标记为脏页,内核将会在合适的时间把脏页的数据写到磁盘中去,以保持高速缓存中的数据和磁盘中的数据是一致的。


bdflush

用来定期将内存中的脏页缓存写到磁盘上的进程


kswapd

处理页面交换的一种守护进程,在内存不足时,将一些进程的页面交换到swap空间之中。