C/C++ 記憶池[嵌入式系統有限度的使用動態配置記憶體]
C/C++ 記憶池[嵌入式系統有限度的使用動態配置記憶體]
資料來源: https://blog.csdn.net/xinghun_4/article/details/5967840
http://tjpm.blog.chinaunix.net/uid-23969156-id-1743561.html
https://blog.csdn.net/weixin_40203143/article/details/85217972
GITHUB: https://github.com/jash-git/C_Memory-_Pool_Project
01.
/* * fpool.h (fixed memory pool) * author: xinghun_4 */ #ifndef _FPOOL_H #define _FPOOL_H int mem_pool_init(int base_size, int links); void mem_pool_destroy(void); void print_mem_pool_info(void); void *mem_malloc(int size); void mem_free(void *ptr); #endif
/* * fpool.c (fixed memory pool) * author: xinghun_4 */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include "fpool.h" #define MEM_POOL_DEBUG #define DEFAULT_BASE_SIZE 4 #define DEFAULT_LINKS 4 #define DEFAULT_BLOCKS 4 #define DEFAULT_INCREMENT_LINKS 4 #define DEFAULT_INCREMENT_BLOCKS 4 #define ALIGN(ADD, SIZE) (((ADD) + ((SIZE) - 1)) & ~((SIZE) - 1)) /* 声明内存块, 前向引用 */ typedef struct _mem_block mem_block_t; /* 内存节点指针 */ typedef union _mem_node { mem_block_t *b_next; /* 指向下一块内存节点 */ char data[1]; /* 内存节点首地址 */ }mem_node_t; /* 内存块 */ struct _mem_block { short index; /* 内存链索引, mem_free 的时候有用 */ mem_node_t n_node; /* 内存节点 */ char pad[2]; }; /* 内存链 */ typedef struct _mem_link { struct _mem_link *l_next; /* 指向下一条内存链 */ short index; /* 内存链索引 */ short blocks; /* 内存链内存块数 */ short free_blocks; /* 内存链空闲内存块数 */ char pad[2]; mem_block_t *b_head; /* 内存链首内存块 */ }mem_link_t; /* 内存池 */ typedef struct _mem_pool { short links; /* 内存链数 */ short base_size; /* 内存节点为base_size的倍数 */ mem_link_t *l_head; /* 首内存链 */ mem_link_t *l_tail; /* 尾内存链 */ }mem_pool_t; static mem_pool_t mem_pool; /* add new memory links to our memory pool */ static int add_mem_link(int links); /* add new memory blocks to our memory link */ static int add_mem_block(mem_link_t *link, int blocks); /* * @base_size: 节点大小单位 * @links: 内存链条数 */ int mem_pool_init(int base_size, int links) { if(base_size <= 0) { base_size = DEFAULT_BASE_SIZE; } else { /* base_size 为 4 的倍数 */ base_size = ALIGN(base_size, DEFAULT_BASE_SIZE); } if(links <= 0) { links = DEFAULT_LINKS; } /* initiate mem_pool */ memset(&mem_pool, 0, sizeof(mem_pool)); mem_pool.base_size = base_size; /* add links into the memory pool */ if(!add_mem_link(links)) { fprintf(stderr, "mem_pool_init::add_mem_link error\n"); return 0; } return 1; } void mem_pool_destroy(void) { mem_link_t *cur_l; mem_block_t *cur_b; cur_l = mem_pool.l_head; while(cur_l) {/* 释放内存链 */ mem_pool.l_head = mem_pool.l_head->l_next; /* 指向下一条内存链 */ cur_b = cur_l->b_head; while(cur_b) {/* 释放所有内存块 */ cur_l->b_head = cur_l->b_head->n_node.b_next; /* 指向下个内存块 */ free(cur_b); cur_b = cur_l->b_head; } cur_l = mem_pool.l_head; } memset(&mem_pool, 0, sizeof(mem_pool_t)); } void print_mem_pool_info(void) { int i; mem_link_t *cur_l = NULL; mem_block_t *cur_b = NULL; cur_l = mem_pool.l_head; if(NULL == cur_l) { printf("/nmemory pool is not exist!\n"); return; } /* memory pool info */ printf("/n/************** Memory pool information **************/\n"); #ifdef MEM_POOL_DEBUG printf("sizeof(mem_node_t) : %d\n", sizeof(mem_node_t)); printf("sizeof(mem_block_t) : %d\n", sizeof(mem_block_t)); printf("sizeof(mem_link_t) : %d\n", sizeof(mem_link_t)); printf("sizeof(mem_pool_t) : %d\n", sizeof(mem_pool_t)); #endif printf("links : %d\n", mem_pool.links); printf("base_size : %d\n", mem_pool.base_size); printf("link head pointer : %x(%d)\n", (int)mem_pool.l_head, (int)mem_pool.l_head); printf("link tail pointer : %x(%d)\n", (int)mem_pool.l_tail, (int)mem_pool.l_tail); while(cur_l) {/* 打印内存链 */ printf("/n#### memory link %d ####\n", cur_l->index); printf("blocks : %d\n", cur_l->blocks); printf("free blocks : %d\n", cur_l->free_blocks); printf("block size : %d\n", cur_l->index * mem_pool.base_size); printf("block head pointer : %x(%d)\n", (int)cur_l->b_head, (int)cur_l->b_head); cur_b = cur_l->b_head; i = 0; while(cur_b) { printf("memory block %d : %x(%d)\n", i++, (int)cur_b, (int)cur_b); cur_b = cur_b->n_node.b_next; } cur_l = cur_l->l_next; } printf("/*****************************************************/\n"); } void *mem_malloc(int size) { int align_size = ALIGN(size, mem_pool.base_size); int index = align_size / mem_pool.base_size - 1; mem_link_t *cur_l = mem_pool.l_head; mem_block_t *cur_b = NULL; mem_node_t *cur_n = NULL; int i; short *p_index; if(index >= mem_pool.links) { printf("no such size(%d) memory block!\n", align_size); return NULL; } /* go to the right link */ for(i = 0; i < index; ++i) { cur_l = cur_l->l_next; } if(0 >= cur_l->free_blocks) {/* no free blocks, expand memory link */ if(!add_mem_block(cur_l, DEFAULT_INCREMENT_BLOCKS)) { fprintf(stderr, "mem_malloc::add_mem_block error\n"); return NULL; } } /* get free block from block head pointer */ cur_b = cur_l->b_head; cur_l->free_blocks--; /* modify memory link node head pointer */ cur_l->b_head = cur_l->b_head->n_node.b_next; p_index = (short *)cur_b; /* 记录索引, 便于 mem_free 找到正确的内存链 */ *p_index = cur_l->index; ++p_index; cur_n = (mem_node_t *)p_index; return (void *)&(cur_n->data[0]); } void mem_free(void *ptr) { short *p_index = (short *)ptr; mem_link_t *cur_l = mem_pool.l_head; mem_block_t *cur_b = NULL; int i; --p_index; /* go to the right link */ for(i = 0; i < *p_index; ++i) { cur_l = cur_l->l_next; } cur_b = (mem_block_t *)p_index; /* 内存链头部插入空闲内存块 */ cur_b->n_node.b_next = cur_l->b_head; cur_l->b_head = cur_b; cur_l->free_blocks++; } /* 返回成功添加的内存链条数 */ static int add_mem_link(int links) { mem_link_t *new_l = NULL; int index = 0; int i = links; int cnt = 0; /* 求得新添加链的索引 */ if(NULL == mem_pool.l_head) { index = 0; } else { index = mem_pool.l_tail->index + 1; } while(i--) { if(NULL == (new_l = (mem_link_t *)malloc(sizeof(mem_link_t)))) { fprintf(stderr, "add_mem_link::malloc mem_link_t error\n"); continue; } /* 初始化新内存链 */ memset(new_l, 0, sizeof(mem_link_t)); new_l->index = index++; /* 新内存链加入内存池 */ if(NULL == mem_pool.l_head) { mem_pool.l_head = new_l; mem_pool.l_tail = new_l; } else { mem_pool.l_tail->l_next = new_l; mem_pool.l_tail = new_l; } mem_pool.links++; ++cnt; if(!add_mem_block(new_l, DEFAULT_INCREMENT_BLOCKS)) { fprintf(stderr, "add_mem_link::add_mem_block error\n"); } } return cnt; } static int add_mem_block(mem_link_t *link, int blocks) { mem_block_t *new_b = NULL; int i = blocks; int cnt = 0; if(NULL == link) { fprintf(stderr, "memory link is NULL!\n"); return 0; } #ifdef MEM_POOL_DEBUG printf("add_mem_block::block_size: %d\n", sizeof(short) + mem_pool.base_size * (link->index + 1)); #endif while(i--) { if(NULL == (new_b = (mem_block_t *)malloc(sizeof(short) + mem_pool.base_size * (link->index + 1)))) { fprintf(stderr, "add_mem_block::malloc mem_block_t error\n"); continue; } /* 初始化新内存块 */ memset(new_b, 0, sizeof(mem_block_t)); new_b->index = link->index; /* 新内存块加入内存链 */ if(NULL == link->b_head) { link->b_head = new_b; } else { new_b->n_node.b_next = link->b_head; link->b_head = new_b; } link->blocks++; link->free_blocks++; ++cnt; } return cnt; }
#include <stdio.h> #include <stdlib.h> #include "fpool.h" void mempool_test_index0(void) { int *t1 = (int *)mem_malloc(sizeof(int)); int *t2 = NULL; int value = 3; if(NULL == t1) { printf("mempool_test_index0:: mem_malloc t1 NULL\n"); return; } print_mem_pool_info(); if(NULL == (t2 = (int *)mem_malloc(sizeof(int)))) { printf("mempool_test_index0:: mem_malloc t2 NULL\n"); return; } print_mem_pool_info(); *t1 = value; printf("mempool_test01:: t1: %d\n", *t1); *t1 *= *t1; *t2 = *t1; (*t2)++; printf("mempool_test01:: t1: %d\n", *t1); printf("mempool_test01:: t2: %d\n", *t2); mem_free(t1); t1 = NULL; /* 不要忘了, 否则若两指针同时指向一块内存会出问题 */ print_mem_pool_info(); mem_free(t2); t2 = NULL; print_mem_pool_info(); } int main() { if(!mem_pool_init(0, 0)) { return -1; } print_mem_pool_info(); mempool_test_index0(); mem_pool_destroy(); print_mem_pool_info(); return 0; }
02.
/***********************mem_pool.h************************ * * * author:bripengandre * * modified by: LaoLiulaoliu * * TODO: thread_safe, different model * * *********************************************************/ #ifndef _MEM_POOL_H_ #define _MEM_POOL_H_ #define BUF_SIZE 100 #define BASE_COUNT 10000 #define STEP_COUNT 1000 typedef union _mem_node { char buf[BUF_SIZE]; union _mem_node *next; } mem_node_t, *pmem_node_t; /* consider of the efficiency, node_cnt can be annotated */ /* used to store block information */ typedef struct _mem_block { mem_node_t *node_head; mem_node_t *node_tail; int node_cnt; /* node count */ struct _mem_block *next; } mem_block_t, *pmem_block_t; /* consider of the efficiency, block_cnt can be annotated */ /* used to store the pool information */ typedef struct _mem_pool { mem_block_t *block_head; // mem_block_t *block_tail; mem_node_t *free_head; int block_cnt; /* block count */ int free_cnt; /* free node count; */ int base; int step; } mem_pool_t, *pmem_pool_t; /* mem_pool will have at least base blocks, and will increase steps a time if needed */ int mem_pool_init(int base, int step); void mem_pool_destroy(void); void print_mem_pool_info(void); /* since the block size is constant, this function need no input parameter */ void *mem_alloc(void); void mem_free(void *ptr); #endif /* _MEM_POOL_H */
/***********************mem_pool.c************************ * * * author:bripengandre * * modified by: LaoLiulaoliu * * *********************************************************/ #include <stdio.h> #include <string.h> #include <stdlib.h> #include "mem_pool.h" /* static functions are the mainly expense of cpu in memory pool */ /* add new memory block to our memory pool */ static int add_mem_block(int cnt); /* init the new block */ static int mem_block_init(int cnt, mem_block_t *block); /* init free_list of the new block */ static int free_list_init(const mem_block_t *block); static mem_pool_t mem_pool; int mem_pool_init(int base, int step) { if(base <= 0) { base = BASE_COUNT; } if(step <= 0) { step = STEP_COUNT; } /* initiate mem_pool */ memset( &mem_pool, 0, sizeof(mem_pool) ); mem_pool.base = base; mem_pool.step = step; /* add the base block(node of base count) into the memory pool */ if( !add_mem_block(base) ) { fprintf(stderr, "mem_pool_init::add_mem_block error\n"); return 0; } return 1; } void mem_pool_destroy(void) { mem_block_t *prev_block, *cur_block; prev_block = NULL; cur_block = mem_pool.block_head; while(cur_block != NULL) { prev_block = cur_block; cur_block = cur_block->next; /* mem_block_init() malloc once,so just free once of the head pointer */ free(prev_block->node_head); free(prev_block); } memset( &mem_pool, 0, sizeof(mem_pool_t) ); } void print_mem_pool_info(void) { int i; mem_block_t *p; if(mem_pool.block_head == NULL) { fprintf(stderr, "memory pool has not been created!\n"); return; } printf("***************memory pool information start*******************\n"); printf("base block size: %d\n", mem_pool.base); printf("increasing block size: %d\n", mem_pool.step); printf("block count: %d\n", mem_pool.block_cnt); printf("current free node count: %d\n", mem_pool.free_cnt); printf("the first block: %#x\n", mem_pool.block_head); //printf("the last block: %#x\n", mem_pool.block_tail); printf("the first free node: %#x\n\n", mem_pool.free_head); for(p = mem_pool.block_head, i = 0; p != NULL; p = p->next, i++) { printf("-----------------block %d-----------------------\n", i+1); printf("node count: %d\n", p->node_cnt); printf("the first node: %#x\n", p->node_head); printf("-------------------------------------------------\n"); } printf("***************memory pool information end*********************\n\n"); } void *mem_alloc(void) { mem_node_t *p; /* no free node ready, attempt to allocate new free node */ if(mem_pool.free_head == NULL) { if( !add_mem_block(mem_pool.step) ) { fprintf(stderr, "mem_alloc::add_mem_block error\n"); return NULL; } } /* get free node from free_list */ p = mem_pool.free_head; mem_pool.free_head = p->next; /* decrease the free node count */ mem_pool.free_cnt--; return p; } void mem_free(void *ptr) { if(ptr == NULL) { return; } /* return the node to free_list */ ((mem_node_t *)ptr)->next = mem_pool.free_head; mem_pool.free_head = ptr; /* increase the free node count */ mem_pool.free_cnt++; } static int add_mem_block(int cnt) { mem_block_t *block; if( (block = malloc(sizeof(mem_block_t))) == NULL ) { fprintf(stderr, "mem_pool_init::malloc block error\n"); return 0; } if( !mem_block_init(cnt, block) ) { fprintf(stderr, "mem_pool_init::mem_block_init error\n"); return 0; } /* insert the new block in the head */ /* for the first time, block->next == NULL */ block->next = mem_pool.block_head; mem_pool.block_head = block; // if(mem_pool.block_tail == NULL) // { // mem_pool.block_tail = block; // } /* insert the new block into the free list */ /* block->node_tail->next == NULL in these two situations of add_mem_block() */ block->node_tail->next = mem_pool.free_head; mem_pool.free_head = block->node_head; mem_pool.free_cnt += cnt; /* increase the block count */ mem_pool.block_cnt++; return 1; } static int mem_block_init(int cnt, mem_block_t *block) { size_t size; mem_node_t *p; if(block == NULL) { return 0; } size = cnt * sizeof(mem_node_t); if( (p = malloc(size)) == NULL ) { fprintf(stderr, "mem_pool_init::malloc node error\n"); return 0; } memset(p, 0, size); memset(block, 0, sizeof(mem_block_t)); block->node_cnt = cnt; block->node_head = p; block->node_tail = p+cnt-1; free_list_init(block); return 1; } static int free_list_init(const mem_block_t *block) { mem_node_t *p, *end; if(block == NULL) { return 0; } /* start initiating free list */ end = block->node_tail; /* block_cnt > 0 */ for(p = block->node_head; p < end; p++) { p->next = (p+1); } p->next = NULL; /* end->next = NULL */ return 1; }
#include <stdio.h> #include <stdlib.h> #include "mem_pool.h" #define ALLOC_COUNT 10 void alloc_test(char *ptr[]) { int i, j; for(i = 0; i < ALLOC_COUNT; i++) { if( (ptr[i] = mem_alloc()) == NULL ) { fprintf(stderr, "mem_alloc error\n"); return; } for(j = 0; j < ALLOC_COUNT; j++) { ptr[i][j] = 'a' + j; } } for(i = 0; i < ALLOC_COUNT; i++) { for(j = 0; j < ALLOC_COUNT; j++) { printf("ptr[%d][%d]=%c ", i, j, ptr[i][j]); } fputc('\n', stdout); } } int main(int argc, char *argv[]) { int base, step; char *ptr1[ALLOC_COUNT], *ptr2[ALLOC_COUNT]; switch(argc) { case 1: base = 0; /* default count */ step = 0; /* default count */ break; case 2: base = atoi(argv[1]); step = 0; break; case 3: base = atoi(argv[1]); step = atoi(argv[2]); break; default: fprintf(stderr, "Usage: %s [ [step]]\n", argv[0]); break; } if( !mem_pool_init(base, step) ) { fprintf(stderr, "mem_pool_init error\n"); return 1; } print_mem_pool_info(); alloc_test(ptr1); print_mem_pool_info(); //mem_free(ptr1[5]); print_mem_pool_info(); alloc_test(ptr2); print_mem_pool_info(); mem_pool_destroy(); /* once again */ if( !mem_pool_init(base, step) ) { fprintf(stderr, "mem_pool_init error\n"); return 1; } print_mem_pool_info(); alloc_test(ptr1); print_mem_pool_info(); mem_free(ptr1[5]); print_mem_pool_info(); alloc_test(ptr2); print_mem_pool_info(); mem_pool_destroy(); return 0; }
03.
#ifndef MEMORYPOOL_H_INCLUDED #define MEMORYPOOL_H_INCLUDED #include <stdlib.h> #include <string.h> #include <stdio.h> typedef struct Memorypool { int mempool_size; int memory_size;//block_size + sizeof(manager information) = mem_size int block_size; int total_memory_cnt; int used_memory_cnt; int auto_extend; struct Memory* free_list; struct Memory* used_list; }memorypool; typedef struct Memory { int memory_size; int block_size; struct Memory* prev; struct Memory* next; struct Memorypool* mp; char* block; }memory; memorypool* memorypool_create(int block_request_size, int memory_init_quantity, _Bool memory_extend); char* memory_malloc(memorypool* mp,int data_size); int memorypool_info_get(memorypool* mp); int memory_free(char** p_bk); int memorypool_destroy(memorypool* mp); memory* memory_creat(int memory_size, memorypool* mp); #endif // MEMORYPOOL_H_INCLUDED
#include "memorypool.h" memorypool* memorypool_create(int block_request_size, int memory_init_quantity, _Bool memory_extend) {//請求最大極限,記憶池數量=>記憶池大小(基底*數量), memorypool* mp = NULL; mp = (memorypool*)malloc(sizeof(memorypool)); memset(mp, 0, sizeof(memorypool)); mp->block_size = block_request_size; mp->memory_size = block_request_size + sizeof(memory); mp->auto_extend = memory_extend; for (int i = memory_init_quantity; i > 0; i--) { memory* mm = NULL; mm = memory_creat(mp->memory_size , mp); } return mp; } char* memory_malloc(memorypool* mp, int data_size) { memory* p_memory = NULL; if (mp->block_size < data_size) { return NULL; } if (NULL == mp->free_list) { if (mp->auto_extend == 1) memory_creat(mp->memory_size, mp); else return NULL; } p_memory = mp->free_list; mp->free_list = mp->free_list->next; p_memory->next = NULL; if (mp->used_list) { mp->used_list->prev->next = p_memory; p_memory->prev = mp->used_list->prev; } else { mp->used_list = p_memory; } p_memory->next = mp->used_list; mp->used_list->prev = p_memory; mp->used_list = p_memory; mp->used_memory_cnt += 1; return p_memory->block; } int memorypool_info_get(memorypool* mp) { printf("current mempool_size:%d\n\ current memory_size:%d\n\ current block_size:%d\n\ total_memory_cnt:%d\nused_memory_cnt:%d\n",mp->mempool_size,mp->memory_size,mp->block_size, \ mp->total_memory_cnt,mp->used_memory_cnt); return 0; } int memory_free(char** p_bk) { memory* p_memory = (memory* )(*p_bk - sizeof(memory)/(sizeof(char)));//正确 p_memory->next->prev = p_memory->prev; p_memory->prev->next = p_memory->next; p_memory->next = NULL; p_memory->prev = NULL; if (p_memory->mp->used_memory_cnt == 1) { p_memory->mp->used_list = NULL; } p_memory->next = p_memory->mp->free_list; p_memory->mp->free_list = p_memory; p_memory->mp->used_memory_cnt -= 1; *p_bk = NULL; return 0; } int memorypool_destroy(memorypool* mp) { memory* mm = NULL; if (mp->free_list) { mm = mp->free_list; mp->free_list = mp->free_list->next; free(mm); mm = NULL; } if (mp->used_list) { mp->used_list->prev->next = NULL; mm = mp->used_list; mp->used_list = mp->used_list->next; free(mm); mm = NULL; } free(mp); return 0; } memory* memory_creat(int memory_size, memorypool* mp) { memory* mm = NULL; char* bk = NULL; char* memory_start = (char*)malloc(memory_size); memset(memory_start, 0, memory_size); mm = (memory*)memory_start; memset(mm, 0, sizeof(memory)); bk = memory_start - sizeof(memory);//错误 bk =memory_start +sizeof(memory)/(sizeof(char));//正确 mm->memory_size = memory_size; mm->block_size = memory_size - sizeof(memory); mm->mp = mp; mm->block = bk; mm->next = mp->free_list; mp->free_list = mm; mp->total_memory_cnt += 1; mp->mempool_size += mp->memory_size; return mm; }
#include <stdio.h> #include <stdlib.h> #include <time.h> #include "memorypool.h" void print_info_line(char *data) { printf("%s---%d\t%s\n",__FILE__, __LINE__,data); } int main() { memorypool* mp = NULL; int memory_init_quantity = 5; _Bool memory_extend = 1; int block_request_size =1024; time_t start = 0; time_t end = 0; int count = 0; mp = memorypool_create(block_request_size, memory_init_quantity, memory_extend);//1024,5,1 print_info_line("memorypool_create"); memorypool_info_get(mp); struct test { int a; int b; }; struct test* p_data; /* start = time(NULL); int i=10; while (i>0) { p_data = (struct test*)memory_malloc(mp, sizeof(struct test)); //p_data = (struct test*)malloc(sizeof(struct test)); memorypool_info_get(mp); p_data->a = 100; memory_free((char**)&p_data); memorypool_info_get(mp); //free(p_data); end = time(NULL); count += 1; if (end == (start + 300)) { printf("%d", count); break; } i--; } */ p_data = (struct test*)memory_malloc(mp, sizeof(struct test)); p_data->a = 100; p_data->b = 200; int Sum = p_data->a + p_data->b; printf("Sum=%d\n",Sum); print_info_line("memory_malloc"); memorypool_info_get(mp); memory_free((char**)&p_data); print_info_line("memory_free"); memorypool_info_get(mp); memorypool_destroy(mp); print_info_line("memorypool_destroy"); return 0; }
One thought on “C/C++ 記憶池[嵌入式系統有限度的使用動態配置記憶體]”
記憶池[Memory Pool]
https://zh.wikipedia.org/wiki/%E8%A8%98%E6%86%B6%E6%B1%A0
記憶池(Memory Pool),又被稱為固定大小區塊規劃(fixed-size-blocks allocation),允許程式設計師以類似 C語言 的 malloc 或是 C++ 的 new 運算元進行動態的記憶體規劃。對於其它動態記憶體規劃的實踐來說,因為會變動記憶體區塊大小導致的碎片問題,導致在實時系統上受限於效能因此,根本無法使用。記憶池提供了一個更有效率的解決方案:預先規劃一定數量的記憶體區塊,使得整個程式可以在執行期規劃 (allocate)、使用 (access)、歸還 (free) 記憶體區塊。
有許多實時作業系統採用了記憶池,IBM 的 Transaction Processing Facility 便是其中一個例子。