Linux物理内存管理概述

在内核态申请内存比在用户态申请内存要更为直接,它没有采用用户态那种延迟分配内存技术。内核认为一旦有内核函数申请内存,那么就必须马上知足该申 请内存的请求,而且这个请求必定是正确合理的。相反,对于用户态申请内存的请求,内核老是尽可能延后分配物理内存,用户进程老是先得到一个虚拟内存区的使用 权,最终经过缺页异常得到一块真正的物理内存。前端

1.物理内存的内核映射

IA32架构中内核虚拟地址空间只有1GB大小(从3GB到4GB),所以能够直接将1GB大小的物理内存(即常规内存)映射到内核地址空间,但超出1GB大小的物理内存(即高端内存)就不能映射到内核空间。为此,内核采起了下面的方法使得内核可使用全部的物理内存。node

1.高端内存不能所有映射到内核空间,也就是说这些物理内存没有对应的线性地址。不过,内核为每一个物理页框都分配了对应的页框描述符,全部的页框描 述符都保存在mem_map数组中,所以每一个页框描述符的线性地址都是固定存在的。内核此时可使用alloc_pages()和 alloc_page()来分配高端内存,由于这些函数返回页框描述符的线性地址。算法

2.内核地址空间的后128MB专门用于映射高端内存,不然,没有线性地址的高端内存不能被内核所访问。这些高端内存的内核映射显然是暂时映射的, 不然也只能映射128MB的高端内存。当内核须要访问高端内存时就临时在这个区域进行地址映射,使用完毕以后再用来进行其余高端内存的映射。api

因为要进行高端内存的内核映射,所以直接可以映射的物理内存大小只有896MB,该值保存在high_memory中。内核地址空间的线性地址区间以下图所示:数组

从图中能够看出,内核采用了三种机制将高端内存映射到内核空间:永久内核映射,固定映射和vmalloc机制。缓存

2.物理内存管理机制

基于物理内存在内核空间中的映射原理,物理内存的管理方式也有所不一样。内核中物理内存的管理机制主要有伙伴算法,slab高速缓存和vmalloc 机制。其中伙伴算法和slab高速缓存都在物理内存映射区分配物理内存,而vmalloc机制则在高端内存映射区分配物理内存。数据结构

伙伴算法架构

伙伴算法负责大块连续物理内存的分配和释放,以页框为基本单位。该机制能够避免外部碎片。框架

per-CPU页框高速缓存函数

内核常常请求和释放单个页框,该缓存包含预先分配的页框,用于知足本地CPU发出的单一页框请求。

slab缓存

slab缓存负责小块物理内存的分配,而且它也做为高速缓存,主要针对内核中常常分配并释放的对象。

vmalloc机制

vmalloc机制使得内核经过连续的线性地址来访问非连续的物理页框,这样能够最大限度的使用高端物理内存。

3.物理内存的分配

内核发出内存申请的请求时,根据内核函数调用接口将启用不一样的内存分配器。

3.1 分区页框分配器

分区页框分配器 (zoned page frame allocator) ,处理对连续页框的内存分配请求。分区页框管理器分为两大部分:前端的管理区分配器和伙伴系统,以下图:

管理区分配器负责搜索一个能知足请求页框块大小的管理区。在每一个管理区中,具体的页框分配工做由伙伴系统负责。为了达到更好的系统性能,单个页框的申请工做直接经过per-CPU页框高速缓存完成。

该分配器经过几个函数和宏来请求页框,它们之间的封装关系以下图所示。

这些函数和宏将核心的分配函数__alloc_pages_nodemask()封装,造成知足不一样分配需求的分配函数。其中,alloc_pages()系列函数返回物理内存首页框描述符,__get_free_pages()系列函数返回内存的线性地址。

3.2 slab分配器

slab 分配器最初是为了解决物理内存的内部碎片而提出的,它将内核中经常使用的数据结构看作对象。slab分配器为每一种对象创建高速缓存。内核对该对象的分配和释放均是在这块高速缓存中操做。一种对象的slab分配器结构图以下:

能够看到每种对象的高速缓存是由若干个slab组成,每一个slab是由若干个页框组成的。虽然slab分配器能够分配比单个页框更小的内存块,但它所需的全部内存都是经过伙伴算法分配的。

slab高速缓存分专用缓存和通用缓存。专用缓存是对特定的对象,好比为内存描述符建立高速缓存。通用缓存则是针对通常状况,适合分配任意大小的物理内存,其接口即为kmalloc()。

3.3 非连续内存区内存的分配

内核经过vmalloc()来申请非连续的物理内存,若申请成功,该函数返回连续内存区的起始地址,不然,返回NULL。vmalloc()和 kmalloc()申请的内存有所不一样,kmalloc()所申请内存的线性地址与物理地址都是连续的,而vmalloc()所申请的内存线性地址连续而 物理地址则是离散的,两个地址之间经过内核页表进行映射。

vmalloc()的工做方式理解起来很简单:

1.寻找一个新的连续线性地址空间;

2.依次分配一组非连续的页框;

3.为线性地址空间和非连续页框创建映射关系,即修改内核页表;

vmalloc()的内存分配原理与用户态的内存分配类似,都是经过连续的虚拟内存来访问离散的物理内存,而且虚拟地址和物理地址之间是经过页表进 行链接的,经过这种方式能够有效的使用物理内存。可是应该注意的是,vmalloc()申请物理内存时是当即分配的,由于内核认为这种内存分配请求是正当 并且紧急的;相反,用户态有内存请求时,内核老是尽量的延后,毕竟用户态跟内核态不在一个特权级。

后记:本文将Linux内核中物理内存管理这部份内容进行框架性总结,对内存管理感兴趣的同窗能够从伙伴算法,slab和vmalloc()三个角度去了解和学习物理内存管理。

相关文章
相关标签/搜索