内存池设计实现

1.设计原理

1.内存池实际就是预先分配不同大小的内存块, 然如果需要调用的时候, 直接把这个块的指针返回.

图中, 就是内存池划分.

2.通过一个链表, 将这些分配的内存块串联起来, 每一块最头部都记录这这个块的信息

3.分配的时候, 会遍历一遍链表, 找到is_used未被置1, pool_size大于或等于分配的大小的内存块(并且这个pool_size必定是内存池最小的那块), 如果找到, 则is_used被置1. 同时返回那个内存块的数据存储的首位置addr + sizeof(pool_t);.

4. 释放则是遍历每个内存块, 比较内存块加上一个pool_t的大小(if (pt + sizeof(pool_t) == p)), 是否和释放的指针相等

2.源码

2.1 头文件

#ifndef POOL_H
#define POOL_H
typedef struct pool{
    unsigned int pool_size;
    unsigned char is_used;
    struct pool *next;
}pool_t;
int init_pool(int arg_num, ...);
void* pool_malloc(unsigned int size);
unsigned char pool_free(void* p);

#endif

2.2 C文件

#include "pool.h"
#include <stdarg.h>
#include <stdlib.h>
#include "./UART/uart.h"

/*
    我们要进入启动文件, 调整一下堆区大小

*/

static pool_t pool_head = {0};

int init_pool(int arg_num, ...)
{
    unsigned char i, j;
    unsigned int pool_size, pool_num;
    pool_t *new_pool, * p;

    p = &pool_head;
    va_list ap;
    va_start(ap, arg_num);

    for (i = 0; i < arg_num / 2; i++){
        pool_size = va_arg(ap, int);
        pool_num = va_arg(ap, int);
        for (j = 0; j < pool_num; j++){
            new_pool = (pool_t*)malloc(pool_size + sizeof(pool_t));
            if (new_pool == NULL){
                return 0;
            }
            new_pool->next = p->next;
            p->next = new_pool;
            new_pool->is_used = 0;
            new_pool->pool_size = pool_size;

            p = &pool_head;
        }
        
    }

    va_end(ap);
    return 1;
}

void* pool_malloc(unsigned int size)
{
    pool_t* p = pool_head.next;
    pool_t* addr = &pool_head, *temp;
    while (p) {
        if (p->is_used == 0 && p->pool_size >= size){
            temp = p;
            if (addr == &pool_head){
                addr = temp;
            }
            else {
                if (addr->pool_size > temp->pool_size) {
                    addr = temp;
                }
            }
        }
        p = p->next;
    }
    if (addr == &pool_head){
        printf("malloc failed\r\n");
        return 0;
    }
    addr->is_used = 1;
    return addr + sizeof(pool_t);
}

unsigned char pool_free(void* p)
{
    unsigned char free_succes = 0;
    pool_t* pt = pool_head.next;
    while (pt){
        if (pt + sizeof(pool_t) == p) {
            free_succes = 1;
            break;
        }
        pt = pt->next;
    }
    pt->is_used = 0;
    return free_succes;
}

2.3 函数介绍

内存池初始化: 

int init_pool(int arg_num, ...);

 初始时一个不定长参数函数, 初始化的时候注意, init_pool(6, 200, 2, 300, 2, 400, 2);第一个参数是后面不定长参数的个数, 第二个参数是分配一个200字节大小的块, 第三个参数是分配200字节块的个数, 依次类推, 但是也要注意不用分配太大,.

注意: 这些都是没在实际项目中使用的, 还没接受过项目的考验, 但是理论上来讲, 如果是裸机代码从运行来看可以直接拿来用, 如果跑RTOS, 我还不能保证, 可能释放和分配要加互斥锁, 防止访问上造成冲突, 或者直接挂起任务调度, 或者进入临界区.如果有兄弟拿到项目, 发现问题,请评论下,我进行修改. 

2.4 测试

void main()
{
	int*p,*p1, *p2, *p3, *p4, *p5, *p6, *p7;
	init_pool(6, 200, 2, 300, 2, 400, 2);

	printf("sizeof(pool_t) = %d", sizeof(pool_t));

	p = (int*)pool_malloc(100);

	p1 = (int*)pool_malloc(100);

	p2 = (int*)pool_malloc(100);

	p3 = (int*)pool_malloc(100);

	p4 = (int*)pool_malloc(100);
	*p4 = 555;
	p5 = (int*)pool_malloc(100);
	
	p6 = (int*)pool_malloc(100);

	pool_free(p5);

	p7 = (int*)pool_malloc(100);

	while (1);
}

需要优化的地方:

1. 增加内存使用情况,可以通过一个函数跟踪当前内存池使用情况,跟踪的是内存块个数的使用情况

2. 目前来看,这个需要去调整单片机的堆大小(缺点一),而堆作为单片机的一部分,调大了,相应的可使用内存就变小了, 而我们使用的时候,肯定不能完全把堆占满(缺点二)。

3. 关于第2点的改善措施:1. 用一个大数组作为整个内存池,内存池的划分在这个大数组的基础上划分。2.内存池占用不满的情况则通过打印使用情况进行调整。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

入门->放弃

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

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

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

打赏作者

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

抵扣说明:

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

余额充值