除了内存堆内存管理方式以外,还可以采取静态内存池的方式,申请内存和释放内存,首先他叫静态内存池,也就是静态的,所谓的静态的就是在编译器编译阶段就已经固定了内存池的大小,内存池被建立以后无法动态释放。
对比与内存堆管理方式:静态内存池不能申请随意大小的内存块,好处是分配效率高,基本不会产生内存碎片,因为申请的大小是固定的。并且静态内存池的方式支持线程挂起操作。
静态内存池的实现需要用到内存池控制块(你会发现其实现方式和线程的同步与通信的实现方式是一个模子刻出来的):
/*内存池控制块*/
struct rt_mempool
{
struct rt_object parent; /*his dad*/
void *start_address; /* 内存池数据区域开始地址 */
rt_size_t size; /* 内存池数据区域大小 */
rt_size_t block_size; /* 内存块大小 */
rt_uint8_t *block_list; /* 内存块列表 */
/* 内存池数据区域中能够容纳的最大内存块数 */
rt_size_t block_total_count;
/* 内存池中空闲的内存块数 */
rt_size_t block_free_count;
/* 因为内存块不可用而挂起的线程列表 */
rt_list_t suspend_thread;
/* 因为内存块不可用而挂起的线程数 */
rt_size_t suspend_thread_count;
};
typedef struct rt_mempool* rt_mp_t; /*内存池控制块指针*/
内存池初始化完的样子:
内存池管理API接口:
1.初始化静态内存池API:
/*返回:RT_EOK 初始化成功 -RT_ERROR 失败*/
rt_err_t rt_mp_init(rt_mp_t mp, /*内存池控制块引用*/
const char* name, /*内存池名称*/
void *start, /*内存池的起始位置*/
rt_size_t size, /*内存池容量*/
rt_size_t block_size);/*内存块大小+4链表指针*/
2.脱离静态内存池API:
/*返回:RT_EOK 成功*/
rt_err_t rt_mp_detach(rt_mp_t mp);/*内存池控制块引用*/
3.分配内存块API:
/*返回:分配的内存块地址 成功 RT_NULL 失败*/
void *rt_mp_alloc (rt_mp_t mp, /*内存池控制块引用*/
rt_int32_t time);/*超时时间*/
4.释放内存块API:
void rt_mp_free (void *block);/*内存块指针*/
静态内存池应用:
/*创建内存块句柄*/
static rt_uint8_t *ptr[50];
/*内存池存储数组*/
static rt_uint8_t mempool[4096];
/*内存池控制块对象*/
static struct rt_mempool mp;
/* 初始化内存池对象 */
rt_mp_init(&mp, "mp1", &mempool[0], sizeof(mempool), 80);
/*从内存池中申请内存块*/
ptr[1] = rt_mp_alloc(&mp, RT_WAITING_FOREVER);
/*释放内存块*/
rt_mp_free(ptr[1]);