内存池的实现

概述:本文介绍用户层内存池的实现

Q:为什么需要内存池?

A:在项目中,用户层通过malloc系统调用申请内存的次数可能很多 ,每一次malloc系统调用 ,都会引起用户态------内核态的切换这样的开销对性能的影响是不容忽视的,尤其是当你为了申请一段很小的空间而调用malloc时,性能的损失达到了最大化

Q:什么是内存池?
解决方案:只调用一次malloc

A:只调用一次malloc申请足够大的内存空间,后续需要使用内存时,从已申请的内存中取出一块,这就是内存池的概念

这样就避免了频繁进行malloc系统调用,大大降低了性能损失

内存池的实现

思路:

1.内存池的空间由一次malloc调用分配

2.此时的内存池是一整块连续的内存空间

3.使用时,每次应该分配出一小块(固定大小或任意大小)

4.用户调用malloc申请内存,应该得到一块空间的起始地址

5.用户free归还一块内存时,这块内存需要能被重复使用

为了简要说明原理,本文介绍分配固定大小的内存池版本

后面使用到的二级指针,不懂的朋友可以先移步博主的 数据结构专栏------二级指针 这篇文章

1.内存池结构体定义:

c 复制代码
typedef struct mempool_s {
    int block_size; // 内存池最小单元大小
    int free_count; // 空余block数量

    char *free_ptr; // 当前空余的块的地址 
    char *mem; // 整个内存池的首地址
} mempool_t;

2.初始化,为内存池申请空间:

c 复制代码
int mp_init(mempool_t *m, int size) { // 初始化内存池,指定大小

    if (!m) return -1;
    if (size < 16) size = 16; // 最小内存池尺寸为 16字节

    m->block_size = size;

    m->mem = (char *)malloc(MEM_PAGE_SIZE); // 为内存池分配空间
    if (!m->mem) return -1;
    m->free_ptr = m->mem;   // 当前空闲的区域指针
    m->free_count = MEM_PAGE_SIZE / size;
    
    // 二级指针
    // 将一整块内存抽象为多块:块大小为size,每一块的首地址的前8个字节保存下一块的首地址
    int i = 0;
    char *ptr = m->free_ptr;
    for (i = 0;i < m->free_count; i++) {
        *(char **)ptr = ptr + size; // 将当前块的首地址的前8个字节保存下一块的首地址
        ptr += size;
    }
    *(char **)ptr = NULL; // 最后一块

    return 0;
}

3.用户层接口:malloc

c 复制代码
void *mp_alloc(mempool_t *m) { // 向内存池申请一块内存
    
    if (!m || m->free_count == 0) return NULL; // 如果内存池不存在或没有剩余空间

    void *ptr = m->free_ptr;

    m->free_ptr = *(char **)ptr; // 更新free指针,指向下一个空余的内存块
    m->free_count --;

    return ptr;
}

4.用户层接口:free

c 复制代码
void mp_free(mempool_t *m, void *ptr) {

    *(char **)ptr = m->free_ptr; // 将即将被回收的块,指向当前空余的块
    m->free_ptr = (char *)ptr; // 将当前空余的块修改为即将回收的块
    // 相当于把回收的块插入空余队列的第一个位置,优先分配回收的块
    m->free_count ++;
}

5.测试函数main

c 复制代码
int  main() { // 测试

    mempool_t m;

    mp_init(&m, 32);

	void *p1 = mp_alloc(&m);
	printf("1: mp_alloc: %p\n", p1);

	void *p2 = mp_alloc(&m);
	printf("2: mp_alloc: %p\n", p2);

	void *p3 = mp_alloc(&m);
	printf("3: mp_alloc: %p\n", p3);

	void *p4 = mp_alloc(&m);
	printf("4: mp_alloc: %p\n", p4);

	mp_free(&m, p2);

	void *p5 = mp_alloc(&m);
	printf("5: mp_alloc: %p\n", p5);

    return 0;
}

推荐学习 https://xxetb.xetslk.com/s/p5Ibb

相关推荐
别说我什么都不会10 小时前
鸿蒙轻内核M核源码分析系列十二 事件Event
操作系统·harmonyos
qq_437896431 天前
动态内存分配算法对比:最先适应、最优适应、最坏适应与邻近适应
操作系统
别说我什么都不会1 天前
鸿蒙轻内核M核源码分析系列十一 (2)信号量Semaphore
操作系统·harmonyos
别说我什么都不会2 天前
鸿蒙轻内核M核源码分析系列十 软件定时器Swtmr
操作系统·harmonyos
别说我什么都不会2 天前
鸿蒙轻内核M核源码分析系列九 互斥锁Mutex
操作系统·harmonyos
别说我什么都不会3 天前
鸿蒙轻内核M核源码分析系列七 动态内存Dynamic Memory
操作系统·harmonyos
别说我什么都不会3 天前
鸿蒙轻内核M核源码分析系列六 任务及任务调度(3)任务调度模块
操作系统·harmonyos
徐徐同学3 天前
【操作系统】操作系统概述
操作系统·计算机系统
守望时空334 天前
Linux内核升级指南
linux·操作系统
塞尔维亚大汉4 天前
OpenHarmony(鸿蒙南向开发)——小型系统内核(LiteOS-A)【用户态内存调测】
操作系统·harmonyos