linux内核内存分配(三、虚拟内存管理)

在分析虚拟内存管理前要先看下linux内核内存的详细分配我开始就是困在这个地方,对内核内存的分类不是很清晰。我摘录其中的一段:

内核内存地址

===========================================================================================================

在linux的内存管理中,用户使用0~3GB的地址空间,而内核只是用了3GB~4GB区间的地址空间,共1GB;非连续空间的物理映射就位于3GB~4GB之间,如下图示0GB 3GB 4GB而关于内核空间中这1GB是如何分配的呢,具体请看下图:

通常会把内核空间中大于896M的空间称作内核空间中的高端内存。内核可以用三种不同的机制将页框映射到高端内存:永久内核映射、临时内核映射和非连续内存分配。本文中将要谈论的是非连续内存分配。 从上图可以知道,在物理内存的末尾和非连续内存区之间插入了一个大小为8MB的区间,这是一个安全区,目的是“捕获”对非连续区的非法访问。出于同样的理由,在其它非连续区间也插入了大小为4KB的安全区。而每个非连续区的大小都是4KB的倍数。如下图:

非连续内存的线性地址空间是从VMALLOC_START~VMALLOC_END,共128MB大小。当内核需要用vmalloc类的函数进行非连续内存分配时,就会申请一个vm_struct结构来描述对应的vmalloc区,若分配多个vmalloc的内存区,那么相邻两个vmalloc区之间的间隔大小至少为4KB,即至少是一个页框大小PAGE——SIZE。如上图。

===============================================================================================================

这里强调下:上面的图示表示的仅仅是虚拟地址,而实际的物理地址是分DMA和常规地址及高端地址的;

linux内核内存大概的就是上面的图示了,其中8MB说是为了安全,防止越界访问(看了很多书,都这么说),就是这8MB虚拟地址不做任何映射(这样仅仅是虚拟地址,没有实际的物理地址浪费)

由上面的图示可以知道,前面896MB(其他架构可以能不是以896MB分割的)就是我们说的内核逻辑地址(记住是内核逻辑地址,如果就说逻辑地址的话应该是指x86架构中虚拟地址中不包括段地址部分,也就是段内偏移部分);这部分内存地址已经在系统初始化的时候和物理页做好了映射,而且是一一映射,我们一般使用的时候就是用该部分的内存地址(kmalloc函数使用就是该部分)。这段内存是非常高效的,因为不需要做其他的映射和修改页表就可以直接使用。本blog是分析下虚拟内存地址的映射,主要是vmalloc函数和ioremap函数;

vmalloc函数

vmalloc函数是驱动模块经常使用的内存分配函数,,该函数返回的虚拟地址连续的(其实这也有疑问,因为上面vmalloc的虚拟地址区有4k分割地址,如果vmalloc分配的虚拟地址很大,那么中间是否有4kb的分割地址?),但是不保证所映射的物理地址也是连续的。它主要对上面的vmalloc_start到vmalloc_end这段内存操作,返回的虚拟地址就是这一部分的。

在大多数情况下,不鼓励使用vmalloc来申请内存,原因: 1、通过vmalloc函数获取的内存使用效率不高(因为要自己做映射,要判断哪些是空闲页等操作);2、有些架构上给vmalloc使用的内存地址非常小,对vmalloc调用可能会因为没有空闲地址而失败;3、不能保证物理地址是连续的,对一些驱动程序来说这是硬伤;综上所述,最好不要用包含vmalloc的代码作为内核的主线代码。

下面大概来说下vmalloc函数的原型:

void *vmalloc(unsigned long size);

该函数的实现有3个步骤:1、在vmalloc区域分配一段连续的虚拟内存地址;2、通过伙伴系统获取物理页;3、通过对页表的操作,把1中获取到的虚拟地址映射到2中分配到物理页上;

注意:

1、上面的图示我们可以看出每个vmalloc虚拟地址之间都有4kb的分割区域(其作用就是防止越界,形成一个空洞,越界时产生异常),所以vmalloc函数实现时,会在size对齐后再增加4kb大小(一个页的大小);

2、在分配物理页时,会从高端地址(上面的图示表示的仅仅是虚拟地址而已,物理内存分配可以看 linux内核内存分配(一、基本概念)中物理页和虚拟地址的映射图)分配,gfp为:GFB_KERNEL | _GFP_HIGHMEM;表示该函数可能睡眠,分配的物理地址来自高端物理页。常规物理页给kmalloc使用;vmalloc函数分配高端物理页时使用alloc_page函数或者alloc_pages_node函数来分配一个整页,多次调用分配函数来完成所有的物理页的分配,这样就不能保证所有的物理页一定连续了。

3、对虚拟地址映射时不会对额外的4k的分割地址进行映射,第2步中也不会对这4k的虚拟分割地址进行分配映射的物理页。

下面是vmalloc的映射图,图来自《深入linux设备驱动程序内核机制》

如果说对云南有进一步的了解的话就是鲜花。

linux内核内存分配(三、虚拟内存管理)

相关文章:

你感兴趣的文章:

标签云: