1、kmalloc函数内幕
函数原型:
#include <linux/slab.h>
void *kmalloc(size_t size, int flags);
(1)flags:
GFP_ATOMIC:
GFP_KERNEL:
GFP_USER:
GFP_HIGHUSER:
GFP_NOIO:
GFP_NOFS:
上面列出的分配标志可以和下面的标志“或”起来:
__GFP_DMA:
__GFP_HIGHMEM:
__GFP_COLD:
__GFP_NOWARN:
__GFP_HIGH:
__GFP_REPEAT:
__GFP_NOFAIL:
__GFP_NORETRY:
2、后备高速缓存
(1)slab分配器实现高速缓存具有kmem_cache_t类型,可以通过调用kmem_cache_create创建:
kmem_cache_t *kmem_cache_create(const char *name, size_t size
size_t offset, unsigned long flags,
void (*constructor) (void *, kmem_cache_t *,
unsigned long flags),
void (*destructor) (void *, kmem_cache_t *,
unsigned long flags));
flags的取值:
SLAB_NO_REAP:
SLAB_HWCACHE_ALIGN:
SLAB_CACHE_DMA:
(2)一旦某个对象的高速缓存被创建,就可以调用kmem_cache_alloc从中分配内存对象:
void *kmem_cache_alloc(kmem_cache_t *cache, int flags);
(3)释放内存对象:
void kmem_cache_free(kmem_cache_t *cache, const void *obj);
(4)释放高速缓存:
int kmem_cache_destroy(kmem_cache_t *cache);
3、内存池(尽量避免使用)
建立内存池对象:
#include <linux/mempool.h>
mempool_t *mempool_create(int min_nr, mempool_alloc_t *alloc_fn,
mempool_free_t *free_fn, void *pool_data);
typedef void *(mempool_alloc_t) (int gfp_mask, void *pool_data);
typedef void (mempool_free_t) (void * slement, void *pool_data);
建立内存池之后,可用如下所示分配和释放对象:
void *mempool_alloc(mempool_t *pool, int gfp_mask);
void mempool_tree(void *element, mempool_t *pool);
用下面的函数来调整mempool的大小:
int mempool_resize(mempool_t *pool, int new_min_nr, int gfp_mask);
如果不再需要内存池,可以用下面的函数将其返回给系统:
void mempool_destroy(mempool_t *pool);
4、get_free_page和相关函数:
(1)分配页可以使用下面的函数:
get_zerod_page(unsigned ing flags);//返回指向新页面的指针并将页面清零。
__get_free_page(unsigned int flags);//类似于get_zerod_page,但不清零。
__get_free_pages(unsigned int flags, unsigned int order);
注:需要将其返回值转换为void *的形式。
(2)当函数不再使用时,可以是用下面的函数之一释放它们:
void free_page(unsigned long addr);
void free_pages(unsigned long addr, unsigned long order);
(3)alloc_pages接口
Linux页分配器的核心代码是alloc_pages_node函数:
struct page *alloc_pages_node(int nid, usigned int flags, unsigned int order);
其中nid为NUMA节点的ID号,表示要在其中分配内存。
这个函数的两个变种:
struct page *alloc_pages(unsigned int flags, unsigned int order);
struct page *alloc_page(unsigned int flags);
释放通过上述途径分配的页面:
void __free_page(struct page *page);
void __free_pages(struct page *page, unsigned int order);
void free_hot_page(struct page *page);
void free_cold_page(struct page *page);
5、vmalloc及其辅助函数
#include <linux/vmalloc>
void *vmalloc(unsigned long size);
void vfree(void *addr);
void *ioremap(unsigned long offset, unsigned long size);
void iounmap(void *addr);
注:
vmalloc与__get_free_pages返回的都是虚拟内存地址。vmalloc中调用了
kmalloc(GFP_KERNEL)来获取页表的存储空间。
6、per-CPU变量
(1)per-CPU变量的声明可见于<linux/percpu.h>中,要在编译期间创建一个per-CPU变量,可以使用下面的宏:
DEFINE_PER_CPU(type, name);
如果该变量是一个数组,需要在type中包含数组维数。例如:
DEFINE_PER_CPU(int[3], my_percpu_array);
(2)关于per-CPU的一些函数:
get_cpu_var(socket_in_use)++;
put_cpu_var(socket_in_use);
访问其他处理器上的副本:
per_cpu(variable, int cpu_id);
动态分配per-CPU变量:
void *alloc_percpu(type);
void *__alloc_percpu(size_t size, size_t align);
动态分配变量的访问:
per_cpu_ptr(void per_cpu_var, int cpu_id);
(3)Per-CPU变量可以导出给模块,但是必须使用特殊版本的宏:
EXPORT_PER_CPU_SYMBOL(per_cpu_var);
EXPORT_PER_CPU_SYMBOL_GPL(per_cpu_var);
要在模块中访问这么个变量则:
DECLARE_PRE_CPU(type, name);
7、获得大的缓冲区:
#include <linux/bootmem.h>
void *alloc_bootmem(unsigned long size);
void *alloc_bootmem_low(unsigned long size);
void *alloc_bootmem_pages(unsigned long size);
void *alloc_bootmem_low_pages(unsigned long size);
释放内存:
void free_bootmem(unsigned long addr, unsigned long size);