Linux内核内存分配函数

i. 分配函数的选择

kmalloc():如果需要连续的物理页,可以使用此函数,这是内核中内存分配的常用方式,也是大多数情况下应该使用的内存分配方式。传递给函数的最常用的标志是GTP_ATOMIC和GTP_KERNEL。前面的标志表示进行不睡眠的高优先级分配。在中断处理程序和其他不能睡眠的代码段中需要。后面的标志可以睡眠,在没有持自旋锁的进程上下文中使用。此函数返回内核逻辑地址。

get_free_pages():如果模块需要分配大块的内存,使用此面向页的分配技术。返回内核逻辑地址。

alloc_pages():想从高端内存中分配,就使用此函数。但返回一个指向page结构的指针。为了获得真正的指针,应该调用kmap(),把高端内存映射到内核的虚拟地址空间。

vmalloc():不需要物理上连续的页,仅仅需要虚拟地址上连续的页。

Slab高速缓存:多次创建和销毁较大的数据结构。

内存池:内核有些地方的内存分配不允许失败,为了确保这种情况的成功分配,内核开发者建立了内存池的抽象。内存池其实就是某种形式的后备高速缓存。mempool_create建立内存池对象,mempool_alloc创建内存池。

perCUP:减少数据锁定,大大减少缓存失效。唯一的要求是要禁止内核抢占。

ii.  alloc_pages()

该函数分配连续的物理页,并返回一个指针,指针指向第一个页的page结构体。可以用kmap()函数把此页转换成逻辑地址。此函数可以在高端内存或普通内存分配物理页。

iii. get_free_pages()

此函数与alloc_pages()作用相同,但它直接返回所请求的第一个页的逻辑地址。此函数不能从高端内存分配物理页。

iv. void *kmalloc(size_t size, int flags)

可以获得以字节为单位的内核内存。参数flags有三类标志:行为描述符,区描述符以及类型。

行为修饰符:不常用,忽略。

描述符:__GFP_DMA从ZONE_DMA分配。

__GFP_HIGHMEM从ZONE_HIGHMENZONG_NORMAL分配。

类型标志:GFP_KERNEL,常规分配方式,可能阻塞。用于进程上下文中。

                     GFP_ATOMIC,高优先级的,不会睡眠。用着中断处理程序,下半部,

不能睡眠的地方

v.  vmalloc

工作方式类似于kmalloc(), 不过虚拟地址连续,物理地址不连续。获得大块内存时使用。

vi. slab高速缓存

slab高速缓存一般用于数据频繁分配和回收,如inode和task_struct数据结构。

1. slab层设计

    Linux内核内存分配函数_第1张图片

2. slab分配器接口使用

    下面以进程描述符task_struct为例说明slab分配器接口使用:

    Linux内核内存分配函数_第2张图片

3. slab着色

    让slab缓存的对象在CPU的cache彼此错开,不会造成CPU cache频频失效

vii. percpu

1. 定义CPU变量

    a) 编译时定义:DEFINE_PER_CPU(type, name);

    b) 动态定义:void *alloc_percpu(type)

                             void *__alloc_percpu(size_t size, size_t,aligh);

        释放CPU变量:void free_percpu(const void *);

2. 获取CPU数据

    a) get_cpu_ptr(ptr); //返回一个void类型指针,指向处理器的ptr拷贝

    b) put_cpu_ptr(ptr);//完成:重新激活内核抢占

3. 实例说明

    Linux内核内存分配函数_第3张图片

4. 返回数据:per_cpu_ptr(ptr,cpu);

    此函数返回指定处理器的唯一数据。这个函数不会禁止内核抢占,如果需要访问另外处理器的数据,需要给数据上锁。

 


你可能感兴趣的:(Linux内核内存分配函数)