转自:http://blog.csdn.net/szkbsgy/article/details/50491216,我根据自己情况做了部分修改。
在编程中,为了避免由于频繁的malloc/free产生内存碎片,通常会在程序中实现自己的内存管理模块,即内存池。内存池的原理:程序启动时为内存池申请一块较大的内存,在程序中使用内存时,都由内存池进行分配,不再使用的内存交给内存池回收,用于再次分配。内存池一般会有如下的接口:memory_pool_init, memory_pool_malloc, memory_pool_free 和 memory_pool_destroy。本文实现了一个简单的内存池,仅用于基础学习。
memory_pool.h
#ifndef __MEMORY_POOL_H__
#define __MEMORY_POOL_H__
#define MAX_POOL_SIZE 1024 * 1024
#define BLOCK_SIZE 16
typedef struct memory_map_talbe
{
char *p_block;
int used;
} Memory_Map_Table;
typedef struct memory_alloc_table
{
char *p_start;
int used;
int block_start_index;
int block_cnt;
}Memory_Alloc_Table;
typedef struct memory_pool
{
char *memory_start;//内存池起始地址, free整个内存池时使用
Memory_Alloc_Table *alloc_table;
Memory_Map_Table *map_table;
int total_size;
int internal_total_size;
int used_size;
int block_size;
int block_cnt;
int alloc_cnt;
} Memory_Pool;
extern Memory_Pool *memory_pool_init(int size);
extern void *Memory_malloc(Memory_Pool *pool, int size);
extern void memory_free(Memory_Pool *pool, void *memory);
extern void memory_pool_destroy(Memory_Pool *pool);
#endif
memroy_pool.c
#include
#include
#include
#include "memory_pool.h"
//获取内存映射表的位置
Memory_Map_Table *map_table_pos(Memory_Pool *pool)
{
Memory_Map_Table *p = (Memory_Map_Table *)(pool->memory_start + sizeof(Memory_Pool));
return p;
}
//获取内存分配表的位置
Memory_Alloc_Table *alloc_talbe_pos(Memory_Pool *pool)
{
Memory_Alloc_Table *p = (Memory_Alloc_Table *)(pool->memory_start + sizeof(Memory_Pool) +
sizeof(Memory_Map_Table) * (pool->block_cnt));
return p;
}
//获得memory在位置
char *memory_pos(Memory_Pool *pool)
{
char *p = (char *)(pool->memory_start + sizeof(Memory_Pool) +
(sizeof(Memory_Map_Table) + sizeof(Memory_Alloc_Table))* pool->block_cnt);
return p;
}
Memory_Pool *memory_pool_init(int size)
{
char *p = NULL;
char *p_memory = NULL;
Memory_Pool *pool = NULL;
Memory_Alloc_Table *alloc_table = NULL;
Memory_Alloc_Table *p_alloc_table = NULL;
Memory_Map_Table *map_table = NULL;
Memory_Map_Table *p_map_table = NULL;
int block_cnt = 0;
int all_size = 0;
int i = 0;
if (size < 0 || size > MAX_POOL_SIZE) {
printf("memory_pool_init(): Invalid size(%d)\n", size);
return pool;
}
block_cnt = ((size + BLOCK_SIZE - 1) / BLOCK_SIZE);
all_size = sizeof(Memory_Pool) + (sizeof(Memory_Map_Table) +
sizeof(Memory_Alloc_Table)) * block_cnt + size;
p = (char *)malloc(all_size);
if (p == NULL) {
perror("Malloc failed\n");
return pool;
}
memset(p, 0, all_size);
pool = (Memory_Pool *)p;
pool->block_cnt = block_cnt;
pool->block_size = BLOCK_SIZE;
pool->internal_total_size = BLOCK_SIZE * block_cnt;
pool->total_size = size;
pool->used_size = 0;
pool->alloc_cnt = 0;
pool->memory_start = p;
p_memory = memory_pos(pool);
map_table = map_table_pos(pool);
for (i = 0; i < block_cnt; i++) {
p_map_table = (Memory_Map_Table *)((char *)map_table + i * sizeof(Memory_Map_Table));
p_map_table->p_block = p_memory + i * BLOCK_SIZE;
p_map_table->used = 0;
}
alloc_table = alloc_talbe_pos(pool);
for (i = 0; i < block_cnt; i++) {
p_alloc_table = (Memory_Alloc_Table *)((char *)alloc_table + i * sizeof(Memory_Alloc_Table));
p_alloc_table->block_cnt = 0;
p_alloc_table->block_start_index = -1;
p_alloc_table->p_start = NULL;
p_alloc_table->used = 0;
}
printf("memory_pool_init: total size: %d, block cnt: %d, block size: %d\n",
pool->total_size, pool->block_cnt, BLOCK_SIZE);
return pool;
}
void *Memory_malloc(Memory_Pool *pool, int size)
{
char *p_start = NULL;
int need_block_cnt = 0;
Memory_Map_Table *map_table = NULL;
Memory_Map_Table *p_map_table = NULL;
Memory_Alloc_Table *alloc_table = NULL;
Memory_Alloc_Table *p_alloc_table = NULL;
int block_cnt = 0;
int start_index = -1;
int i = 0;
if (size <= 0) {
printf("Invalid size(%d)\n", size);
return p_start;
}
if (size > pool->total_size) {
printf("%d is more than total size\n", size);
return p_start;
}
if (size > pool->total_size - pool->used_size) {
printf("Free memory(%d) is less than allocate(%d)\n",
pool->total_size - pool->used_size, size);
return NULL;
}
need_block_cnt = (size + BLOCK_SIZE - 1) / BLOCK_SIZE;
map_table = map_table_pos(pool);
start_index = -1;
for (i = 0; i < pool->block_cnt; i++) {
p_map_table = (Memory_Map_Table *)((char *)map_table + i * sizeof(Memory_Map_Table));
if (p_map_table->used) {
//printf("before alloc: map index: %d is used\n", i);
block_cnt = 0;
start_index = -1;
continue;
}
if (start_index == -1) {
start_index = i;
//printf("start_index: %d\n", start_index);
}
block_cnt++;
if (block_cnt == need_block_cnt) {
break;
}
}
if (start_index == -1) {
printf("No available memory to used\n");
return NULL;
}
alloc_table = alloc_talbe_pos(pool);
for (i = 0; i < pool->block_cnt; i++) {
p_alloc_table = (Memory_Alloc_Table *)((char *)alloc_table + i * sizeof(Memory_Alloc_Table));
if (p_alloc_table->used == 0) {
break;
}
p_alloc_table = NULL;
}
if (p_alloc_table == NULL) {
return NULL;
}
p_map_table = (Memory_Map_Table *)((char *)map_table + sizeof(Memory_Map_Table) * start_index);
p_alloc_table->p_start = p_map_table->p_block;
p_alloc_table->block_start_index = start_index;
p_alloc_table->block_cnt = block_cnt;
p_alloc_table->used = 1;
for (i = start_index; i < start_index + block_cnt; i++) {
p_map_table = (Memory_Map_Table *)((char *)map_table + i * sizeof(Memory_Map_Table));
//printf("map index: %d is used\n", i);
p_map_table->used = 1;
}
printf("Alloc size: %d, Block: (start: %d, end: %d, cnt: %d)\n", size,
start_index, start_index + block_cnt - 1, block_cnt);
pool->alloc_cnt++;
pool->used_size += size;
return p_alloc_table->p_start;
}
void memory_free(Memory_Pool *pool, void *memory)
{
Memory_Map_Table *map_table = NULL;
Memory_Map_Table *p_map_table = NULL;
Memory_Alloc_Table *alloc_table = NULL;
Memory_Alloc_Table *p_alloc_table = NULL;
int i = 0;
int block_start_index = 0;
int block_cnt = 0;
if (memory == NULL) {
printf("memory_free(): memory is NULL\n");
return;
}
if (pool == NULL) {
printf("Pool is NULL\n");
return;
}
alloc_table = alloc_talbe_pos(pool);
for (i = 0; i < pool->alloc_cnt; i++) {
p_alloc_table = (Memory_Alloc_Table *)((char *)(alloc_table) + i * sizeof(Memory_Alloc_Table));
if (p_alloc_table->p_start == memory) {
block_start_index = p_alloc_table->block_start_index;
block_cnt = p_alloc_table->block_cnt;
break;//add by wangk
}
}
if (block_cnt == 0) {
return;
}
map_table = map_table_pos(pool);
printf("Block: free: start: %d, end: %d, cnt: %d\n", block_start_index,
block_start_index + block_cnt -1, block_cnt);
for (i = block_start_index; i < block_start_index + block_cnt; i++) {
p_map_table = (Memory_Map_Table *)((char *)map_table + i * sizeof(Memory_Map_Table));
p_map_table->used = 0;
printf("block:%d, no used\n", i);
}
p_alloc_table->used = 0;
pool->used_size -= block_cnt * BLOCK_SIZE;
}
void memory_pool_destroy(Memory_Pool *pool)
{
if (pool == NULL) {
printf("memory_pool_destroy: pool is NULL\n");
return;
}
free(pool);
pool = NULL;
}
main.c
#include
#include "memory_pool.h"
#define if_mem_is_null(pool, ptr) do{\
if(ptr != NULL) \
memory_free(pool, ptr);\
}while(0);
int main(void)
{
Memory_Pool *pool = NULL;
char *p1 = NULL;
char *p2 = NULL;
char *p3 = NULL;
char *p4 = NULL;
int i = 0;
pool = memory_pool_init(1024);
if (pool == NULL)
printf("memory pool init failed\n");
p1 = (char *)Memory_malloc(pool, 64);
if (p1 == NULL)
printf("p1,Malloc failed\n");
else
printf("p1,malloc success\n");
p2 = (char *)Memory_malloc(pool, 32);
if (p2 == NULL)
printf("p2, Malloc failed\n");
else
printf("p2, Malloc success\n");
p3 = (char *)Memory_malloc(pool, 128);
if (p3 == NULL)
printf("p3, Malloc failed\n");
else
printf("p3, Malloc success\n");
if_mem_is_null(pool, p2);
p4 = (char *)Memory_malloc(pool, 96);
if (p4 == NULL)
printf("p4, Malloc failed\n");
else
printf("p4, Malloc success\n");
memory_pool_destroy(pool);
return 0;
}
Memory_Pool: 用于内存属性结构,用于整个内存池的管理
Memory_Map_Table: 内存映射表,是Memory的映射,用于管理Memory
Memory_Alloc_Table: 内存分配表,用于记录分配过的内存
Memory:实际用于分配的内存
说明:内存的分配是以块为单位的,向上取整,不足一块的按一块处理。
缺点:
1. 实际的可分配内存只是内存池中Memory表示的结构,其它的结构都是内存池管理用的,会造成内存浪费,而且是内存池越大,管理结构越大,浪费内存越多
2. 如果块大小设为64B, 而申请1B,会造成63B的浪费,所以申请内存最好是块大小的整数倍。
3. 当无内存可分配时,内存池不会自动增长