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);
}