内存池管理 库 分享

简洁

内存池是一种 预先分配一大块内存,然后再按需 “划小块” 提供内存的机制

撰写原由

文档

模块:hali_memory_pool
功能:线程池 
实现:未采用常见的分块化结构,更是根据所需空间大小,动态组建——块链表
	优点:1.小数量大需求情况下,对于头的占用减少 2.避免了分块导致的分配大小>需求大小的问题
	缺点:


结构体:
struct Hali_SubModule_Pool {
	struct Hali_SubModule_Pool *next; /* 指向下一个可用内存块的位置,为NULL就是没有下一个 */

	unsigned short module_size; /* 该内存区域块的大小 ,柔性数组指向空间的大小 */
	unsigned char used; /* 该内存区域是否有使用 */
	unsigned char reserved;

	unsigned char *data[]; /* 柔性数组,指向真实可分配使用空间 */
};

#define SUB_MODULE_HEAD_SIZE sizeof(struct Hali_SubModule_Pool)

typedef struct Hali_Memory_Pool {
	unsigned char *pool_start_address; /* 内存池起始地址 */

	unsigned char *pool_rightmost_address;

	struct Hali_SubModule_Pool *list;
}Hali_Memory_Pool;
Hali_Memory_Pool hali_p;

一个块的架构
头 + data

头的构成:
4Bytes	——	*next
2Bytes	——	module_size
1Bytes	——	used
1Bytes	——	reserved

我们暂且将一个“ 头 + data ”的结构称为块
当 块 与 块相邻时,会判断是否可以融合,即将两个块融合为一个块,从而节省对 头 的开支

请求空间,分配大小时,也会尽量分配给合适的块供给,以免导致内存池碎片化

.c

#include "hali_memory_pool.h"
#include <string.h>
#include <stdlib.h>

/**
 * 内存池 优点:更高的速度,更低的碎片,更低的系统开销
 * 缺点: 对于空间管理上的冗余字段的浪费现象
 *
 * 力求 设计一种较好的内存池管理
 */

#define TAG "hali_memory_pool"
#define HALI_MEMORY_DEBUG_SWITCH_FLAG	(1)
#ifdef HALI_MEMORY_DEBUG_SWITCH_FLAG
 #define HALI_MD_LOGE	printf // error
 #define HALI_MD_LOGW	printf // warning
 #define HALI_MD_LOGI	printf // info
 #define HALI_MD_LOGD	printf // debug
 #define HALI_MD_LOGV	printf // verbose
#else
 #define HALI_MD_LOGE	
 #define HALI_MD_LOGW	
 #define HALI_MD_LOGI	
 #define HALI_MD_LOGD	
 #define HALI_MD_LOGV	
#endif

#define DIFF_MAX_VALUE (unsigned int)(-1)

enum HALI_RETURN_TYPE {
	HALI_RETURN_ERROR = -1,
	HALI_RETURN_OK = 0,
};

struct Hali_SubModule_Pool {
	struct Hali_SubModule_Pool *next; /* 指向下一个可用内存块的位置,为NULL就是没有下一个 */

	unsigned short module_size; /* 该内存区域块的大小 ,柔性数组指向空间的大小 */
	unsigned char used; /* 该内存区域是否有使用 */
	unsigned char reserved;

	unsigned char *data[]; /* 柔性数组,指向真实可分配使用空间 */
};

#define SUB_MODULE_HEAD_SIZE sizeof(struct Hali_SubModule_Pool)

typedef struct Hali_Memory_Pool {
	unsigned char *pool_start_address; /* 内存池起始地址 */

	unsigned char *pool_rightmost_address;

	struct Hali_SubModule_Pool *list;
}Hali_Memory_Pool;
Hali_Memory_Pool hali_p;

static unsigned char hali_memory_pool_inited = 0;


static void* hali_malloc(int size)
{
#if HALI_POOL_MEMORY_USE_PSRAM
	psram_malloc(size);
#else
	malloc(size);
#endif
}

static void hali_free(void *data) 
{
#if HALI_POOL_MEMORY_USE_PSRAM
	psram_free(data);
#else
	free(data);
#endif	
}

static void ensure_rightmost_address(void)
{
	struct Hali_SubModule_Pool *pos = (struct Hali_SubModule_Pool *)hali_p.pool_start_address;
	struct Hali_SubModule_Pool *pos_last = NULL;

	do {
		pos_last = pos;
		hali_p.pool_rightmost_address = (unsigned char*)pos_last;
		pos = (struct Hali_SubModule_Pool *)((unsigned char*)pos + SUB_MODULE_HEAD_SIZE + pos->module_size);
		if (pos && pos->next != pos_last) { // 说明这就是最右边的 block 了
			break;
		} else if (!pos) {
			break;
		}
	} while(1);
}

static struct Hali_SubModule_Pool *get_last_node(struct Hali_SubModule_Pool *node)
{
	ensure_rightmost_address();

	struct Hali_SubModule_Pool *pos = (struct Hali_SubModule_Pool *)hali_p.pool_rightmost_address;

	for (; pos; pos = pos->next) {
		if (pos->next == node) {
			return pos;
		}
	}

	return NULL; // 说明并没有前一个
}

void *hali_memory_pool_alloc(int size)
{
	if (size < 0) {
		HALI_MD_LOGE("%s -> args is invalid\r\n", TAG);
		return NULL;
	}
	ensure_rightmost_address();
	
	// NOTE 寻找最适合的 块,分配空间
	struct Hali_SubModule_Pool *pos = (struct Hali_SubModule_Pool *)hali_p.pool_rightmost_address;
	struct Hali_SubModule_Pool *new = NULL;
	struct Hali_SubModule_Pool *pos_last = NULL;
	struct Hali_SubModule_Pool *match_pos = NULL;
	unsigned int diff_min_size = DIFF_MAX_VALUE;

	// REVIEW 或许后面这个算法还可以优化???
	for (; pos; pos = pos->next) { // 轮询一周,找到大小与size最接近的 block
		if (pos->used == 0 && pos->module_size >= size) {
			if ((pos->module_size - size) < diff_min_size) {
				diff_min_size = pos->module_size - size;
				match_pos = pos;
			}
		} else { 
			continue;
		}
	}

	// NOTE 融合操作只在free的时候才有,也就是代表申请空间时,不存在融合操作,只有分块操作
	if (diff_min_size != DIFF_MAX_VALUE) { // NOTE 这原本就是一个块,是已经分为了块的
		new = match_pos;
		// new->data = match_pos->data; // 柔性数组 本身就是指向这个位置 显示表达就是如此
		new->next = match_pos->next;
		new->module_size = size;
		new->used = 1;

		if (diff_min_size >= SUB_MODULE_HEAD_SIZE) { // 说明剩余大小还可以成块
			match_pos = (struct Hali_SubModule_Pool *)((unsigned char*)match_pos + SUB_MODULE_HEAD_SIZE + size);
			match_pos->module_size = diff_min_size - SUB_MODULE_HEAD_SIZE; // 此值可以为0
			match_pos->used = 0;
			// match_pos->data = (unsigned char*)match_pos + SUB_MODULE_HEAD_SIZE; // 同上柔性数组解释
			match_pos->next = new;
			pos_last = get_last_node(match_pos);
			if (pos_last) {
				pos_last->next = match_pos;
			}
		} else { // 剩余空间大小不足以成块,直接冗余分配出去 (因为无法形成头即无法执行融合块操作)
			new->module_size += diff_min_size;
		}

		return (void *)new->data;
	}

	return NULL; // 分配不了
}

int hali_memory_pool_free(void *data) // 释放空间需要注意 ( 标记为不合法时,需要再自动归碎为整数 )
{
	if (data == NULL) {
		HALI_MD_LOGE("%s -> args is invalid\r\n", TAG);
		return HALI_RETURN_ERROR;
	}
	ensure_rightmost_address();

	struct Hali_SubModule_Pool *pos = (struct Hali_SubModule_Pool *)hali_p.pool_rightmost_address;
	struct Hali_SubModule_Pool *pos_last = NULL;
	struct Hali_SubModule_Pool *pos_last_last = NULL;
	struct Hali_SubModule_Pool *pos_next = NULL;

	for (; pos; pos = pos->next) {
		if (pos->data == data) { // 找到了
			pos_last = get_last_node(pos);
			if (pos->next) { // 存在两边都有的情况
				pos_next = pos->next;
				if (pos_next->used == 0) { // 左边可融合
					if (pos_last && pos_last->used == 0) { // 左边右边都可以融合 就融合成一个大的
						pos_next->module_size = pos_next->module_size + SUB_MODULE_HEAD_SIZE + pos->module_size + SUB_MODULE_HEAD_SIZE + pos_last->module_size;
						memset(pos_next->data, 0, pos_next->module_size);
						return HALI_RETURN_OK;
					} else { // 只能和左边融合
						pos_next->module_size = pos_next->module_size + SUB_MODULE_HEAD_SIZE + pos->module_size;
						memset(pos_next->data, 0, pos_next->module_size);
						return HALI_RETURN_OK;
					}
				} else { // 只需要考虑右边可不可以融合
					goto JUST_RIGHT;
				}	
			} else { // 只有右边节点指向过来
JUST_RIGHT:
				if (pos_last && pos_last->used == 0) { // 前面一个节点是未使用的 合并
					pos_last_last = get_last_node(pos_last);
					if (pos_last_last) {
						pos_last_last->next = pos;
					}
					pos->module_size = pos->module_size + SUB_MODULE_HEAD_SIZE + pos_last->module_size;
					pos->used = 0;
					memset(pos->data, 0, pos->module_size);
					return HALI_RETURN_OK;
				} else { // 前面一个节点是使用了的,无法合并,直接表示未再使用即可
					pos->used = 0;
					memset(pos->data, 0, pos->module_size);
					return HALI_RETURN_OK;
				}
			}

		} else {
			continue;
		}
	}

	// 这里返回 说明根本就找不到这个block
	return HALI_RETURN_ERROR;
}

/**
 * 为线程池总初始化,并分配成一个 “块”
 * @return  HALI_RETURN_OK:成功 HALI_RETURN_ERROR:失败
 */
static int hali_memory_pool_malloc(void)
{
	hali_p.pool_start_address = hali_malloc(HALI_POOL_MEMORY_SIZE);
	if (hali_p.pool_start_address == NULL) {
		HALI_MD_LOGE("%s -> malloc failed,please ensure\r\n", TAG);
		return HALI_RETURN_ERROR;
	}
	hali_p.pool_rightmost_address = hali_p.pool_start_address;

	hali_p.list = (struct Hali_SubModule_Pool *)hali_p.pool_start_address;
	hali_p.list->next = NULL;
	hali_p.list->module_size = HALI_POOL_MEMORY_SIZE - SUB_MODULE_HEAD_SIZE;
	hali_p.list->used = 0;
	// hali_p.list->data = hali_p.pool_start_address + SUB_MODULE_HEAD_SIZE; // 同上柔性数组解释

	return HALI_RETURN_OK;
}

/**
 * 释放整个线程池
 * @return  HALI_RETURN_OK:成功 HALI_RETURN_ERROR:失败
 */
static int hali_memory_pool_free_all(void)
{
	if (hali_p.pool_start_address) {
		hali_free(hali_p.pool_start_address);
	} else {
		return HALI_RETURN_ERROR;
	}

	return HALI_RETURN_OK;
}

int hali_memory_pool_init(void)
{
	if (hali_memory_pool_inited == 1) {
		HALI_MD_LOGW("%s -> pool init already init\r\n", TAG);
		return HALI_RETURN_ERROR;
	}
	int ret = -1;

	ret = hali_memory_pool_malloc();
	if (ret != HALI_RETURN_OK) {
		HALI_MD_LOGD("%s -> malloc module failed,memory pool init failed\r\n\r\n", TAG);
		return HALI_RETURN_ERROR;
	}

	return HALI_RETURN_OK;
}


int hali_memory_pool_deinit(void)
{
	if (hali_memory_pool_inited == 1) {
		HALI_MD_LOGW("%s -> pool deinit not init yet\r\n", TAG);
		return HALI_RETURN_ERROR;
	}

	int ret = -1;

	ret = hali_memory_pool_free_all();
	if (ret != HALI_RETURN_OK) {
		HALI_MD_LOGD("%s -> free module failed,memory pool deinit failed\r\n\r\n", TAG);
		return HALI_RETURN_ERROR;
	}

	return HALI_RETURN_OK;
}

// test code under

static void print_pool_free_size(void)
{
	unsigned int free_sum_size = 0;
	unsigned short block_num = 0;
	struct Hali_SubModule_Pool *pos = NULL;

	ensure_rightmost_address();
	pos = (struct Hali_SubModule_Pool *)hali_p.pool_rightmost_address;

	for (; pos; pos = pos->next) {
		if (pos->used == 0) {
			free_sum_size += (pos->module_size + SUB_MODULE_HEAD_SIZE);
		}
		block_num++;
	}

	HALI_MD_LOGD("%s -> free sum size is %d\r\n", TAG, free_sum_size);
	HALI_MD_LOGD("%s -> block num is %d\r\n", TAG, block_num);
}

int main(void)
{
	HALI_MD_LOGD("%s -> test begin\r\n", TAG);

	hali_memory_pool_init();
	print_pool_free_size();

	void *data_0 = hali_memory_pool_alloc(200); 
	if (data_0 != NULL) {
		HALI_MD_LOGD("%s -> alloc data_0 ok\r\n", TAG);
	}
	print_pool_free_size();
	if (hali_memory_pool_free(data_0) == HALI_RETURN_OK) {
		HALI_MD_LOGD("%s -> free data_0 ok\r\n", TAG);
	}
	print_pool_free_size();

	void *data_1 = hali_memory_pool_alloc(100); 
	if (data_1 != NULL) {
		HALI_MD_LOGD("%s -> alloc data_1 ok\r\n", TAG);
	}
	print_pool_free_size();
	void *data_2 = hali_memory_pool_alloc(100); 
	if (data_2 != NULL) {
		HALI_MD_LOGD("%s -> alloc data_2 ok\r\n", TAG);
	}
	print_pool_free_size();
	if (hali_memory_pool_free(data_1) == HALI_RETURN_OK) {
		HALI_MD_LOGD("%s -> free data_1 ok\r\n", TAG);
	}
	print_pool_free_size();
	if (hali_memory_pool_free(data_2) == HALI_RETURN_OK) {
		HALI_MD_LOGD("%s -> free data_2 ok\r\n", TAG);
	}
	print_pool_free_size();

	return 0;
}

.h

#ifndef __HALI_MEMORY_POOL_H__
#define __HALI_MEMORY_POOL_H__

#ifdef _cplusplus
extern "C" {
#endif

/**
 * 内存池
 */

#include "stdio.h"

#define HALI_POOL_MEMORY_USE_PSRAM	(0)

#define HALI_POOL_MEMORY_SIZE	8192 // memory pool size


void *hali_memory_pool_alloc(int size); 
int hali_memory_pool_free(void *data);

int hali_memory_pool_init(void); // 申请一大段区域用于使用
int hali_memory_pool_deinit(void); // 



#ifdef _cplusplus
}
#endif
#endif // end __HALI_MEMORY_POOL_H__

结尾

欢迎交流指正~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值