[笔记分享] [OS] Linux的内存管理

来源:互联网 发布:乔艾莉·波妮身世知乎 编辑:程序博客网 时间:2024/06/05 20:35

Platform: msm8x60
Kernel: 2.6

1.1 介绍
在内核中分配内存不像用户空间分配内存那么简单,如果分配出错,就会导致整个系统崩溃,而且内核内存没用户空间那么奢侈。


1.2 页
内核管理内存以页为单位,这个也是基于MMU来划分的。在32位体系上, 大小为4K。用struct page表示:

这里写图片描述


1.3 区
由于硬件限制,内核因此将内存划分为几个区,不同设备访问不同区域,如下:

这里写图片描述

但是这并不代表某种用途的区一定要对应的设备才能访问。要知道的是,内核如此划分只是为了在方便在逻辑上对内存进行管理。

每个区用struct zone 表示,如下:

这里写图片描述
这里写图片描述


1.4 分配和释放页
下面这些函数都以页为最小单位进行分配,最核心函数:

这里写图片描述

gfp_mask我们一般用GFP_KERNEL。Order表示分配1<<order个连续的物理页,返回的为被分配的第一个页的指针。可以用下面函数转换成逻辑地址使用:

这里写图片描述

当不需要用到页像直接到的逻辑地址时,我们可用:

这里写图片描述

从代码可看出,其实__get_free_pages()只是前两个函数的组合而已。当我们只需要一页时,我们可以用下面函数:

这里写图片描述

当需要返回全是0的页面时,我们就用下面这函数:

这里写图片描述

其实也就是多传了个__GFP_ZERO参数而已。下面用表总结下:

这里写图片描述

当不要分配的这些页时,Linux也提供了相对应的函数来释放页,如下:
这里写图片描述


1.5 kmalloc
当你需要以页为单位的连续物理页时,前一小节讲的函数非常有用,但是对常用的字节为单位分配来说,我们就可以用kmalloc()。定义如下:

这里写图片描述

该函数分配至少size大小内存,所分配的物理页也是连续的,基于slab分配,后面我们会讲到。
对于这里的flags我们有必要说下,这也就是前面说的gfp_mask值。可用的行为修饰符如下:

这里写图片描述

但是我们一般不会直接用,而是用到多个的组合,所以Linux又定义了一组宏:

这里写图片描述
这里写图片描述

内核中最常用的标志是GFP_KERNEL, 这种分配可能引起睡眠。另一个是GFP_ATOMIC,这个标志不能睡眠,而且分配成功的几率比较小。至于该什么时候要使用哪种标志,可参照下表:

这里写图片描述

相应的,释放内存函数用kfree, kfree(NULL)是安全。

这里写图片描述


1.6 vmalloc
vmalloc()类似于kmalloc(),只不过前者分配的内存虚拟地址是连续,但是它的物理地址则不需要连续。

vmalloc()为了将不连续的物理页转换成虚拟地址上连续的页,需要建立专门的页表项,页必须要一个个地映射,这就导致TLB抖动比直接内存映射大得多。所以,不到挖不得已我们才用,一般我们在获得大块内存时。如内核模块加载需要的内存。

函数定义如下:

这里写图片描述

另外需要注意的是vmalloc()可能引起睡眠,所以不能在中断上下文中使用,也不允许在阻塞的地方使用。相对应的内存释放函数如下:

这里写图片描述


1.7 slab
slab存在的目的主要是为了更好地管理空闲链表的频繁分配和回收。Slab层把不同对象划分为高速缓存组,每个高速缓存都存放不同类型的对象,每个对象对应一个高速缓存。然后这些高速缓存又被划分为多个slab,slab由一个或多个物理连续页组成,一般由一个页组成。这种策略能减少内存碎片。之间关系图如下:

这里写图片描述

高速缓存由kmem_cache_t结构表示:

这里写图片描述

其中kem_list3 *nodelists[MAX_NUMNODES];这个参数包含了slab_full、slab_partial、slab_empty这三种链表,也就是说所有可表示的slabl类型都放在这个元素中。

Slab结构如下:

这里写图片描述

Slab结构可在slab内存之内和之外分配。Slab可以创建新的slab,本质上通过__get_free_pages()分配实现,如下:

这里写图片描述

slab层只有给定的高速缓存无空间时才调用此函数。当可用内存变得紧缺时,系统才会调用释放函数,或者是显示调用释放高速缓存时。

创建高速缓存函数如下:

这里写图片描述

该函数会睡眠。相应的销毁高速缓存函数如下:
这里写图片描述

在销毁之前一定要确保如下条件:
1. 高速缓冲中的所有slab为空。
2. 在抵用kmem_cache_destroy()期间确保不再访问这个高速缓存了。

在创建了高速缓存后,我们就要分配一个对象,如下:

这里写图片描述

正如前面所说,当高速缓存无空slab时,我们通过kmem_getpages()获得新的页。相对应的释放对象函数如下:

这里写图片描述

因此,如果要频繁创建很多同类型的对象,那么就可以考虑使用slab,这样就不用自己实现空闲链表了。

原创粉丝点击