kmalloc_kfree

0. 简介

kmalloc()是linux kernel提供的申请内存的API,一般用法:p = kmalloc(size, GFP_KERNEL),其中size代表需要申请的内存大小。GFP_KERNEL代表申请内存的行为,允许睡眠等,常用此标志申请内存。

  • 当kmalloc()申请小于8KB内存时,是用 slub分配器 分配/释放 内存

  • 当kmalloc()申请大于8KB内存时,是用 buddy分配器 分配/释放 内存

kfree()是linux kernel提供的释放内存的API,一般用法:kfree(p),其中p代表用kmalloc()申请内存时返回的指针。

kmalloc()/kfree()申请/释放小于8KB内存时,相关初始化操作是开机启动过程中完成,具体的调用流程是start_kernel() -> mm_init() -> kmem_cache_init()

1. 分析源码

我们使用kmalloc()/kfree()时会通过#include <linux/slab.h>导入函数的原型,但是在导入函数原型前,需要通过配置CONFIG_SLUBCONFIG_SLOB来选择小内存分配/释放算法,如下:

/* include/linux/slab.h */
#ifdef CONFIG_SLUB
#include <linux/slub_def.h>
#elif defined(CONFIG_SLOB)
#include <linux/slob_def.h>
#else
#include <linux/slab_def.h>
#endif

通过查找.configinclude/generated/autoconf.h,可知目前使用slub分配器进行小内存分配/释放。

1.1 分配内存

kmalloc()定义,如下:

__builtin_constant_p()是gcc内置的函数,判断size是否为常量? 当size不是常量时,执行__kmalloc()函数

__kmalloc()定义,如下:

判断size是否大于slub分配器支持分配最大的内存大小?它是等于二页大小,即 当一页大小等于4KB时,SLUB_MAX_SIZE等于8KB

如果成立,执行kmalloc_large() -> __get_free_pages(),从buddy分配器中分配内存 并且 返回分配到的内存地址

否则 执行get_slab()kmalloc_caches[]数组获得对应sizekmem_cachekmalloc_caches[]在linux kernel启动过程中完成初始化),最后执行slab_alloc()从对应sizekmem_cache中获得内存 并且 返回分配到的内存地址

1.2 释放内存

kfree()定义,如下:

如果x是NULL,直接返回;否则,通过virt_to_head_page()x获得slab的首页地址page,然后调用slab_free()

1.3 初始化

kmem_cache_init()定义,如下:

首先调用create_kmalloc_cache()对kmem_cache结构体进行初始化,分别是kmalloc_caches[22]的第0~14个数组成员初始化,每一个数组成员存放object分别为kmem_cache_nodekmalloc-96kmalloc-192kmalloc-2^n( 3 <= n <= 14),最后初始化kmem_size变量,kmem_size变量代表kmem_cache结构体的大小

create_kmalloc_cache()定义,如下:

首先调用kmem_cache_open()对kmem_cache的相关资源进行初始化,然后将kmem_cache放入slab_caches链表,最后创建/proc/slabinfo相关条目

Last updated