内存池及其实现
来源:互联网 发布:macbook pro软件 编辑:程序博客网 时间:2024/05/15 03:57
在本文,将用C语言实现不同类型的内存池,它们的原型分别来自于Linux内核的mempool、mysql的my_alloc、nginx的ngx_palloc。为了能在脱离原工程后简单的使用这些内存池,对原来的代码进行了稍微的修改。下面的正文中,只给出了部分代码,完整的代码可从http://download.csdn.net/detail/it_pcode/6633733处下载
linux的mempool
mempool一次性申请N个大小为M的内存块,在你使用过程中并不释放。mempool内存池,实际上是后备内存,只有在内存紧张时,在申请内存资源失败时,才会从内存池中获取所需的内存。在创建内存池时,需要自己定义内存的申请和释放函数,并内存池内存块的最小个数。
创建内存池
/** * mempool_create - create a memory pool * @min_nr: the minimum number of elements guaranteed to be * allocated for this pool. * @alloc_fn: user-defined element-allocation function. * @free_fn: user-defined element-freeing function. * @pool_data: optional private data available to the user-defined functions. * * this function creates and allocates a guaranteed size, preallocated * memory pool. The pool can be used from the mempool_alloc() and mempool_free() * functions. This function might sleep. Both the alloc_fn() and the free_fn() * functions might sleep - as long as the mempool_alloc() function is not called * from IRQ contexts. */mempool_t *mempool_create(int min_nr, mempool_alloc_t *alloc_fn,mempool_free_t *free_fn, void *pool_data) {return mempool_create_node(min_nr, alloc_fn, free_fn, pool_data, -1);}/*该函数进行实际的内存池创建工作*/mempool_t *mempool_create_node(int min_nr, mempool_alloc_t *alloc_fn,mempool_free_t *free_fn, void *pool_data, int node_id) {mempool_t *pool;pool = malloc(sizeof(*pool));if (!pool)return NULL;pool->elements = malloc(min_nr * sizeof(void *));if (!pool->elements) {free(pool);return NULL;}pool->min_nr = min_nr;pool->pool_data = pool_data;pool->alloc = alloc_fn;pool->free = free_fn;/* * First pre-allocate the guaranteed number of buffers. */while (pool->curr_nr < pool->min_nr) {void *element;element = pool->alloc(pool->pool_data);if (!element) {free_pool(pool);return NULL;}add_element(pool, element);}return pool;}
销毁内存池
/** * mempool_destroy - deallocate a memory pool * @pool: pointer to the memory pool which was allocated via * mempool_create(). * * this function only sleeps if the free_fn() function sleeps. The caller * has to guarantee that all elements have been returned to the pool (ie: * freed) prior to calling mempool_destroy(). */void mempool_destroy(mempool_t *pool) {free_pool(pool);}static void free_pool(mempool_t *pool) {while (pool->curr_nr) {void *element = remove_element(pool);pool->free(element, pool->pool_data);}free(pool->elements);free(pool);}
申请内存
/** * mempool_alloc - allocate an element from a specific memory pool * @pool: pointer to the memory pool which was allocated via * mempool_create(). * @gfp_mask: the usual allocation bitmask. * * this function only sleeps if the alloc_fn() function sleeps or * returns NULL. Note that due to preallocation, this function * *never* fails when called from process contexts. (it might * fail if called from an IRQ context.) */void * mempool_alloc(mempool_t *pool, int mask) {void *element;element = pool->alloc(pool->pool_data);if (element != NULL)return element;if (pool->curr_nr > 0) {element = remove_element(pool);return element;}return NULL;}
释放内存
/** * mempool_free - return an element to the pool. * @element: pool element pointer. * @pool: pointer to the memory pool which was allocated via * mempool_create(). * * this function only sleeps if the free_fn() function sleeps. */void mempool_free(void *element, mempool_t *pool) {if (element == NULL)return;if (pool->curr_nr < pool->min_nr) {if (pool->curr_nr < pool->min_nr) {add_element(pool, element);return;}}pool->free(element, pool->pool_data);}
内存池使用实例
void * alloc_fn(void * pool_data) {int *data = (int *) pool_data;return malloc(*data);}void free_fn(void *elem, void * pool_data) {free(elem);}void test_mempool() {mempool_t *pool = NULL;int d = 10;char *str;pool = mempool_create(20, alloc_fn, free_fn, &d);str = (char *) mempool_alloc(pool, 0);if (NULL == str)printf("cannot get memory for mempool_alloc for str\n");strcpy(str, "hello\n");puts(str);mempool_free(str, pool);puts(str);}
mysql内存池
/* Initialize memory root SYNOPSIS init_alloc_root() mem_root - memory root to initialize block_size - size of chunks (blocks) used for memory allocation (It is external size of chunk i.e. it should include memory required for internal structures, thus it should be no less than ALLOC_ROOT_MIN_BLOCK_SIZE) pre_alloc_size - if non-0, then size of block that should be pre-allocated during memory root initialization. DESCRIPTION This function prepares memory root for further use, sets initial size of chunk for memory allocation and pre-allocates first block if specified. Altough error can happen during execution of this function if pre_alloc_size is non-0 it won't be reported. Instead it will be reported as error in first alloc_root() on this memory root. */void init_alloc_root(MEM_ROOT *mem_root, uint block_size,uint pre_alloc_size __attribute__((unused))) {DBUG_ENTER("init_alloc_root");mem_root->free = mem_root->used = mem_root->pre_alloc = 0;mem_root->min_malloc = 32;mem_root->block_size = block_size - ALLOC_ROOT_MIN_BLOCK_SIZE;mem_root->error_handler = 0;mem_root->block_num = 4; /* We shift this with >>2 */mem_root->first_block_usage = 0;if (pre_alloc_size) {if ((mem_root->free = mem_root->pre_alloc = (USED_MEM*) my_malloc(pre_alloc_size + ALIGN_SIZE(sizeof(USED_MEM)),MYF(0)))){mem_root->free->size= pre_alloc_size+ALIGN_SIZE(sizeof(USED_MEM)); mem_root->free->left= pre_alloc_size; mem_root->free->next= 0; }}DBUG_VOID_RETURN;}
gptr alloc_root(MEM_ROOT *mem_root, unsigned int Size) {uint get_size, block_size;gptr point;reg1 USED_MEM *next = 0;reg2 USED_MEM **prev;DBUG_ENTER("alloc_root");DBUG_ASSERT(alloc_root_inited(mem_root));Size = ALIGN_SIZE(Size);if ((*(prev = &mem_root->free)) != NULL){if ((*prev)->left < Size&& mem_root->first_block_usage++>= ALLOC_MAX_BLOCK_USAGE_BEFORE_DROP&& (*prev)->left < ALLOC_MAX_BLOCK_TO_DROP){next = *prev;*prev = next->next; /* Remove block from list */next->next = mem_root->used;mem_root->used = next;mem_root->first_block_usage = 0;}for (next = *prev; next && next->left < Size; next = next->next)prev = &next->next;}if (!next) { /* Time to alloc new block */block_size = mem_root->block_size * (mem_root->block_num >> 2);get_size = Size + ALIGN_SIZE(sizeof(USED_MEM));get_size = max(get_size, block_size);if (!(next = (USED_MEM*) my_malloc(get_size, MYF(MY_WME)))) {if (mem_root->error_handler)(*mem_root->error_handler)();return ((gptr) 0); /* purecov: inspected */}mem_root->block_num++;next->next = *prev;next->size = get_size;next->left = get_size - ALIGN_SIZE(sizeof(USED_MEM));*prev = next;}point = (gptr) ((char*) next + (next->size - next->left));/*TODO: next part may be unneded due to mem_root->first_block_usage counter*/if ((next->left -= Size) < mem_root->min_malloc) { /* Full block */*prev = next->next; /* Remove block from list */next->next = mem_root->used;mem_root->used = next;mem_root->first_block_usage = 0;}DBUG_RETURN(point);}
/* Deallocate everything used by alloc_root or just move used blocks to free list if called with MY_USED_TO_FREE SYNOPSIS free_root() rootMemory root MyFlagsFlags for what should be freed: MY_MARK_BLOCKS_FREEDDon't free blocks, just mark them free MY_KEEP_PREALLOCIf this is not set, then free also the preallocated block NOTES One can call this function either with root block initialised with init_alloc_root() or with a bzero()-ed block. It's also safe to call this multiple times with the same mem_root. */void free_root(MEM_ROOT *root, myf MyFlags) {reg1 USED_MEM *next, *old;DBUG_ENTER("free_root");if (!root) /* QQ: Should be deleted */DBUG_VOID_RETURN; /* purecov: inspected */if (MyFlags & MY_MARK_BLOCKS_FREE){mark_blocks_free(root);DBUG_VOID_RETURN;}if (!(MyFlags & MY_KEEP_PREALLOC))root->pre_alloc = 0;for (next = root->used; next;) {old = next;next = next->next;if (old != root->pre_alloc)my_free((gptr) old, MYF(0));}for (next = root->free; next;) {old = next;next = next->next;if (old != root->pre_alloc)my_free((gptr) old, MYF(0));}root->used = root->free = 0;if (root->pre_alloc) {root->free = root->pre_alloc;root->free->left = root->pre_alloc->size - ALIGN_SIZE(sizeof(USED_MEM));TRASH_MEM(root->pre_alloc);root->free->next = 0;}root->block_num = 4;root->first_block_usage = 0;DBUG_VOID_RETURN;}
void test_myalloc() {MEM_ROOT root;char *str;init_alloc_root(&root, 1 << 12, 1 << 10);str = (char *) alloc_root(&root, 1024 * sizeof(double));if (NULL == str)printf("cannot get memory for alloc root for str\n");strcpy(str, "hello\n");puts(str);//mark free, can be used againfree_root(&root, MY_MARK_BLOCKS_FREE);//free, can not be usedfree_root(&root, 0);}
nginx内存池
nginx对内存的管理分为大内存与小内存,当某一个申请的内存大于某一个值时,就需要从大内存中分配空间,否则从小内存中分配空间。
nginx中的内存池是在创建的时候就设定好了大小,在以后分配小块内存的时候,如果内存不够,则是重新创建一块内存串到内存池中,而不是将原有的内存进行扩充。当要分配大块内存时,则是在内存池外面再分配空间进行管理的,称为大块内存池。
Nginx内存池中大内存块和小内存块的分配与释放是不一样的,我们在使用内存池时,可以使用ngx_palloc进行分配,使用ngx_pfree释放。而对于大内存,这样做是没有问题的,而对于小内存就不一样了,分配的小内存,不会进行释放。因为大内存块的分配只对前3个内存块进行检查,否则就直接分配内存,所以大内存块的释放必须及时。小内存是在销毁内存池的时候释放的。
创建内存池
ngx_pool_t *ngx_create_pool(size_t size) {ngx_pool_t *p;ngx_log_t *log = NULL;p = ngx_memalign(NGX_POOL_ALIGNMENT, size, log);if (p == NULL) {return NULL;}p->d.last = (u_char *) p + sizeof(ngx_pool_t);p->d.end = (u_char *) p + size;p->d.next = NULL;p->d.failed = 0;size = size - sizeof(ngx_pool_t);p->max = (size < NGX_MAX_ALLOC_FROM_POOL) ? size : NGX_MAX_ALLOC_FROM_POOL;p->current = p;p->chain = NULL;p->large = NULL;p->cleanup = NULL;p->log = log;return p;}
销毁内存池
void ngx_destroy_pool(ngx_pool_t *pool) {ngx_pool_t *p, *n;ngx_pool_large_t *l;ngx_pool_cleanup_t *c;for (c = pool->cleanup; c; c = c->next) {if (c->handler) {c->handler(c->data);}}for (l = pool->large; l; l = l->next) {if (l->alloc) {ngx_free(l->alloc);}}for (p = pool, n = pool->d.next; /* void */; p = n, n = n->d.next) {ngx_free(p);if (n == NULL) {break;}}}
申请内存
void *ngx_palloc(ngx_pool_t *pool, size_t size) {u_char *m;ngx_pool_t *p;if (size <= pool->max) {p = pool->current;do {m = ngx_align_ptr(p->d.last, NGX_ALIGNMENT);if ((size_t) (p->d.end - m) >= size) {p->d.last = m + size;return m;}p = p->d.next;} while (p);return ngx_palloc_block(pool, size);}return ngx_palloc_large(pool, size);}
释放内存
ngx_int_t ngx_pfree(ngx_pool_t *pool, void *p) {ngx_pool_large_t *l;for (l = pool->large; l; l = l->next) {if (p == l->alloc) {ngx_free(l->alloc);l->alloc = NULL;return NGX_OK;}}return NGX_DECLINED;}
内存池使用实例
void test_ngxpalloc(){ngx_pool_t * pool = ngx_create_pool(1024);char *str;str = (char *) ngx_alloc(100);if (NULL == str)printf("cannot get memory for mempool_alloc for str\n");strcpy(str, "hello\n");puts(str);ngx_int_t res = ngx_pfree(pool, str);printf("free result is %d\n", res);puts(str);}
- 内存池及其实现
- C++内存池的概念及其实现
- KVM 内存虚拟化及其实现
- KVM 内存虚拟化及其实现
- KVM 内存虚拟化及其实现
- KVM 内存虚拟化及其实现
- kvm内存虚拟化及其实现
- 动态内存与智能指针及其实现
- 共享内存及其用mmap实现共享内存
- 线程池及其实现
- 内存管理:算法及其c/c++实现 翻译一
- 内存管理:算法及其c/c++实现 翻译二
- 内存管理:算法及其c/c++实现 翻译三
- 内存管理:算法及其c/c++实现 翻译四
- 内存管理:算法及其c/c++实现 翻译五
- 内存管理:算法及其c/c++实现 翻译六
- 内存管理:算法及其c/c++实现 翻译七
- 动态内存和智能指针及其实现方法
- c#各种运算符
- shell判断一个变量是否为空
- eclipse 国际化的插件 properties
- 如何确定电缆组件的性能
- Git 使用记录
- 内存池及其实现
- sqlserver实现结果集的合并(干货)
- 由12306.cn谈谈网站性能技术
- 新接触oracle数据库需要了解的东西
- [Oracle] 别被View 整伤了
- 面试题:写一个memmove函数
- ios中将NSString类型转化为NSMutableDictionary类型
- Linux下中文包、中文输入法的安装
- F5亮相vForum:应用交付助力企业深挖虚拟化价值