Linux内核模块实现内存池(mempool_t)

文章详细介绍了Linux内核模块如何使用mempool_t实现内存池,包括内存池的工作原理、mempool_t的使用方法和数据结构。通过内存池可以减少内存分配和释放的开销,避免内存碎片,提高系统性能。文章还提供了一个内核模块创建内存池的示例代码,并讨论了mempool_t的优点和缺点。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、概述

什么是内存池?
内存池(memory pool)是一种内存管理机制,用于管理一定数量的预分配内存块。内存池在应用程序启动时就会分配一定数量的内存块,并在需要时从内存池中获取内存块,而不是使用常规的malloc或new等内存分配函数来动态分配内存。使用内存池可以显著降低内存分配和释放的开销,并且可以避免内存碎片的产生,从而提高应用程序的性能和可靠性。内存池通常用于高性能的服务器程序、嵌入式系统和实时系统等场景中。
在这里插入图片描述
mempool_t是Linux内核提供的一种内存池实现,包含于<linux/mempool.h>头文件中。mempool_t提供了一种简单、高效的内存池管理方法,可以用于在内核模块中管理预分配的内存块。mempool_t支持对内存块的分配、回收和管理,并提供了多种内存池算法以适应不同的应用场景。使用mempool_t可以显著降低内存分配和释放的成本,避免内存碎片的产生,提高内核模块的性能和可靠性。

Linux内核模块内存池的创建使用函数:

(1)kmem_cache_create():创建内存缓存。

(2)mempool_create():创建内存池。

(3)mempool_destroy():释放内存池。

(4)kmem_cache_destroy():释放内存缓存。

(5)函数 mempool_alloc(mempool_t *pool,gfp_t gfp_mask) 功能:直接从内存池当中分配一个内存元素。void *p = mempool_alloc(pool,GFP_KERNEL);

(6)函数 page_address() 功能:获取物理页的逻辑地址。

二、内存池的实现

2.1、内存池的工作原理

  1. 在初始化时,从操作系统申请一块连续的物理内存,称为内存池。
  2. 将内存池按照固定大小分成多个内存块。
  3. 将这些内存块用链表、栈或其他数据结构连接起来,形成一个内存块池。
  4. 当需要分配内存时,从内存块池中获取一个内存块,并将其标记为已分配。
  5. 当不需要使用内存块时,将其标记为未分配,放回到内存块池中。
  6. 当内存块池中无可用内存块时,可以选择动态扩展内存池。

内存池的主要优势在于可以避免动态分配内存时产生的内存碎片,同时也避免了重复调用内存分配器的开销。由于内存块是预先分配的,因此内存池的内存分配速度相对较快。
在这里插入图片描述

在Linux内核中,mempool_t通过使用kmem_cache_t来实现内存池。kmem_cache_t是一种内存高速缓存器,可以用于高效地分配预定义大小的内存块。mempool_t在初始化时会创建一个kmem_cache_t对象,并分配一定数量的内存块。当需要分配内存时,mempool_tkmem_cache_t中获取内存块并返回。当不需要使用内存块时,将其返回到kmem_cache_t中。

2.2、mempool_t的使用方法

mempool_t的使用方法如下:

  1. 包含<mempool.h>头文件。

  2. 定义mempool_t对象。

    mempool_t *pool;
    
  3. 使用mempool_create()函数创建内存池,并指定内存块大小、内存池中内存块的数量、内存对齐方式等参数。

    pool = mempool_create(min_nr, alloc_size, flags);
    
  4. 使用mempool_alloc()函数从内存池中获取内存块。

    void *ptr = mempool_alloc(pool, flags);
    
  5. 使用获取到的内存块进行操作。

  6. 使用mempool_free()函数将内存块释放回内存池中。

    mempool_free(ptr, pool);
    
  7. 在不需要使用内存池时,使用mempool_destroy()函数释放内存池。

    mempool_destroy(pool);
    

注意:在使用mempool_t时,需要确认内存池中的内存块是否足够,如果内存块不足,可以使用mempool_resize()函数动态扩展内存池。同时,为了避免内存泄漏,需要确保使用完内存块后及时将其释放回内存池中。

2.3、mempool_t数据结构

typedef struct mempool_s {
	spinlock_t lock;
	int min_nr;		/* nr of elements at *elements */
	int curr_nr;		/* Current nr of elements at *elements */
	void **elements;//保留元素的指针数组

	void *pool_data;//相关私有数据
	mempool_alloc_t *alloc;
	mempool_free_t *free;
	wait_queue_head_t wait;//内存池为空时的等待队列
} mempool_t;

通过自旋锁保护对象字段。

三、实现一个内核模块中的内存池

步骤:

  1. 定义初始化模块和退出模块函数。
  2. 定义kmem_cache、mempool_t全局变量。
  3. 在初始化模块函数调用kmem_cache_create和mempool_create函数,创建内存池。
  4. 退出模块调用mempool_destroy和kmem_cache_destroy释放内存。
  5. 模块初始化操作和退出函数调用module_init()和module_exit()。
  6. 其他的声明信息,比如许可协议、作者、模块功能描述等等。
/* 头文件和全局变量地声明*/
#include <linux/mm.h>
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/mempool.h>
#include <linux/blkdev.h>

static int __init mempool_create_InitFunc(void);
static void __exit mempool_create_ExitFunc(void);

struct kmem_cache *pmycache = NULL;
static mempool_t *mypool=NULL;
#define MEMSIZE 10240

// 模块初始化函数
int __init mempool_create_InitFunc(void)
{
    pmycache = kmem_cache_create("MyselfCache",10240,0, SLAB_HWCACHE_ALIGN, NULL);
    if(NULL==pmycache)
    {
        printk("执行:kmem_cache_create(...)函数失败,请重新检查?\n");
    }        
    else
    {
        printk("创建slab缓存成功!\n");
        printk("MyselfCache Cache大小为: %d\n", kmem_cache_size(pmycache));

        // 基于slab缓存创建6个初始元素的内存池
        mypool=mempool_create(6, mempool_alloc_slab, mempool_free_slab, pmycache);
        if(NULL == mypool)
        {
            printk("执行:mempool_create()函数失败,请重新检查?\n");
            return 0;
        }
        else
        {
            printk("创建内存池成功!\n");
            printk("内存池中元素最大个数,min_nr = %d\n", mypool->min_nr);
        }
    }
    return 0;
}

// 模块退出函数
void __exit mempool_create_ExitFunc(void)
{
    // 释放内存池
    if(NULL != mypool)
    {
        mempool_destroy(mypool);
        printk("执行:mempool_destroy()函数释放内存池成功!\n");
    }

    // 释放slab缓存
    if(NULL != pmycache)
    {
        kmem_cache_destroy(pmycache);
        printk("执行:kmem_cache_destroy()函数释放slab缓存成功!\n");
    }
    printk("内核模块退出成功!\n");
}

/* 模块初始化操作和退出函数调用 */
module_init(mempool_create_InitFunc);
module_exit(mempool_create_ExitFunc);

MODULE_LICENSE("GPL"); /* 描述模块代码接受的软件许可协议 */
MODULE_AUTHOR("Lion Long"); /* 描述模块的作者信息:包括作者姓名及邮箱等等 */
MODULE_DESCRIPTION(" kernel module : mempool_create/mempool_destroy"); /* 简要描述此模块用途及功能介绍*/

Makefile

obj-m:=mc.o	

CURRENT_PAHT:=$(shell pwd) 
LINUX_KERNEL:=$(shell uname -r)   

LINUX_KERNEL_PATH:=/usr/src/linux-headers-$(LINUX_KERNEL)
all:

	make -C $(LINUX_KERNEL_PATH) M=$(CURRENT_PAHT) modules

clean:

	make -C $(LINUX_KERNEL_PATH) M=$(CURRENT_PAHT) cleals

四、小结

实际使用中可根据具体场景进行内存池创建和使用,内存池的使用调用mempool_alloc函数。

mempool_t的主要优点和缺点如下:

优点:

  1. 内存池可以减少内存分配和释放的开销,提高内存分配的效率。

  2. 内存池可以避免内存碎片的产生,提高内存管理的效率和可靠性。

  3. 内存池可以支持多种内存分配算法,适用于不同的应用场景。

  4. 内存池可以动态扩展,可以根据需要分配更多的内存块。

缺点:

  1. 内存池需要预先分配一定大小的内存,因此会占用一定的内存空间。

  2. 内存池可能会浪费一些内存空间,因为每个内存块的大小都是固定的。

  3. 内存池的实现需要额外的代码和管理工作,可能会增加代码复杂度和维护成本。

  4. 内存池的性能取决于内存块大小的选择,如果选择不当,可能会影响性能。

mempool_t适合在高负载、高并发的应用场景中使用,可以提高内存管理的效率和可靠性。但是,需要根据实际需求选择合适的内存块大小和内存池大小,避免浪费内存和影响性能。
在这里插入图片描述

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Lion 莱恩呀

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值