作用:内核分配连续物理内存的接口函数,在虚拟地址空间上也是连续的。
与vmalloc的比较:
相同点:都是用于内核空间内存分配,对应的虚拟地址空间连续,且按字节为单位。
异同点:kmalloc分配的物理内存是连续的,vmalloc分配的物理内存可以不连续,但是虚拟地址空间连续。kmalloc分配的物理内存受限于页面最高阶数及页面大小,vmalloc则只受限于系统内存大小。kmalloc既支持大块内存分配也支持小块内存分配,大块内存使用页面分配器,小内存使用slab分配器,而vmalloc用于大块内存分配器,并且最好分配内存大小是整页级的,否则会导致内存空间浪费。
一次分配的最大内存数量,不能超过系统页面最高阶数,比如页面最高阶数MAX_ORDER为11,那么最大的分配内存数量为 2^10 * 4K = 4M,在__alloc_pages里限制。调用栈如下:
kmalloc
|-> kmalloc_large # 分配内存大于一个页面
| |-> kmalloc_order_trace
| |-> kmalloc_order
| |-> alloc_pages # 调用物理页面分配器分配内存
| |-> alloc_pages_node
| |-> __alloc_pages_node
| |-> __alloc_pages # 检查分配页面阶数是否大于等于最高阶
|
|
|
|-> __kmalloc # 分配内存小于一个页面,通过slab分配器分配内存
|-> __do_kmalloc
|-> kmalloc_slab
| |-> kmalloc_caches
|-> slab_alloc
|-> slab_pre_alloc_hook
|-> kfence_alloc
|-> cache_alloc_debugcheck_before
|-> __do_cache_alloc
|-> cache_alloc_debugcheck_after
|-> prefetchw
|-> slab_want_init_on_alloc
|-> slab_post_alloc_hook
测试代码kmalloc_test.c
// kmalloc_test.c
#include <linux/init.h>
#include <linux/module.h>
#include <linux/slab.h>
static int *p = NULL;
static int __init kmalloc_test_init(void)
{
p = kmalloc(4 * 1024 * 1024, GFP_KERNEL);
printk(KERN_INFO "address: %p\n", p);
return 0;
}
static void __exit kmalloc_test_exit(void)
{
printk("exit\n");
if (p != NULL)
kfree(p);
}
module_init(kmalloc_test_init);
module_exit(kmalloc_test_exit);
MODULE_LICENSE("GPL");
Makefile如下:
obj-m+=kmalloc_test.o
CONFIG_MODULE_SIG=n
all:
make -C /lib/modules/$(shell uname -r)/build/ M=$(PWD) modules
clean:
make -C /lib/modules/$(shell uname -r)/build/ M=$(PWD) clean
测试结果如下图所示,插入内核模块分配一块4M(阶数为10)大小的物理内存块,对应的阶数为10,阶数为10的内存块从548减少为547,删除内核模块回收内存块,阶数为10的内存块数量增加一,变为548。
kmalloc提供的分配内存接口:
// 头文件 <linux/slab.h>
kmalloc:分配连续物理内存空间,内存地址上的内容随机。
kzalloc:分配连续物理内存,并将所分配内存空间设置为0。
kmalloc_node:指定的numa节点上分配连续物理内存空间。
kzalloc_node:指定的numa节点上分配连续的物理内存空间,并设置为0。
上述分配接口对应的释放内存接口:kfree
kvmalloc:根据分配内存大小调用kmalloc,或vmalloc,防止内存分配失败。
kvzalloc:根据分配内存大小调用kmalloc或vmalloc分配物理内存。
kvmalloc_node:指定的numa节点上根据分配内存大小调用kmalloc或vmalloc分配物理内存,防止内存分配失败。
kvmalloc_array:同kvzalloc,一次性分配多个,并返回数组。
kvcalloc:同kvmalloc_array,并将分配的内存空间设置为0.
对应的释放内存接口:kvfree