文章插图
提供给用户的内存申请api申请的内存以size做区分,如果大于4k就分配大块内存,小于4k就去block里面划分 。
//分配内存void *mp_malloc(struct mp_pool_s *pool, size_t size) {if (size <= 0) {return NULL;}if (size > PAGE_SIZE - sizeof(struct mp_node_s)) {//largereturn mp_malloc_large(pool, size);}else {//smallunsigned char *mem_addr = NULL;struct mp_node_s *cur = NULL;cur = pool->current;while (cur) {mem_addr = mp_align_ptr(cur->last, MP_ALIGNMENT);if (cur->end - mem_addr >= size) {cur->quote++;//引用+1cur->last = mem_addr + size;return mem_addr;}else {cur = cur->next;}}return mp_malloc_block(pool, size);// open new space}}void *mp_calloc(struct mp_pool_s *pool, size_t size) {void *mem_addr = mp_malloc(pool, size);if (mem_addr) {memset(mem_addr, 0, size);}return mem_addr;}
小块内存block扩容所有的block都 e n d − l a s t < s i z e end - last < size end−last<size 时,进行扩容,将新block的last后移即可 。
【图文结合 带你用纯C实现一个内存池】//new block 4kvoid *mp_malloc_block(struct mp_pool_s *pool, size_t size) {unsigned char *block;int ret = posix_memalign((void **) &block, MP_ALIGNMENT, PAGE_SIZE); //4Kif (ret) {return NULL;}struct mp_node_s *new_node = (struct mp_node_s *) block;new_node->end = block + PAGE_SIZE;new_node->next = NULL;unsigned char *ret_addr = mp_align_ptr(block + sizeof(struct mp_node_s), MP_ALIGNMENT);new_node->last = ret_addr + size;new_node->quote++;struct mp_node_s *current = pool->current;struct mp_node_s *cur = NULL;for (cur = current; cur->next; cur = cur->next) {if (cur->failed++ > 4) {current = cur->next;}}//now cur = last nodecur->next = new_node;pool->current = current;return ret_addr;}
分配大块内存//size>4kvoid *mp_malloc_large(struct mp_pool_s *pool, size_t size) {unsigned char *big_addr;int ret = posix_memalign((void **) &big_addr, MP_ALIGNMENT, size); //sizeif (ret) {return NULL;}struct mp_large_s *large;//released struct large resumeint n = 0;for (large = pool->large; large; large = large->next) {if (large->alloc == NULL) {large->size = size;large->alloc = big_addr;return big_addr;}if (n++ > 3) {break;// 为了避免过多的遍历,限制次数}}large = mp_malloc(pool, sizeof(struct mp_large_s));if (large == NULL) {free(big_addr);return NULL;}large->size = size;large->alloc = big_addr;large->next = pool->large;pool->large = large;return big_addr;}
释放内存如果是大块内存,找到之后直接释放;如果是小块内存,将引用计数减1,如果引用计数为0则重置last 。
//释放内存void mp_free(struct mp_pool_s *pool, void *p) {struct mp_large_s *large;for (large = pool->large; large; large = large->next) {//大块if (p == large->alloc) {free(large->alloc);large->size = 0;large->alloc = NULL;return;}}//小块 引用-1struct mp_node_s *cur = NULL;for (cur = pool->head; cur; cur = cur->next) {//printf("cur:%pp:%pend:%pn", (unsigned char *) cur, (unsigned char *) p, (unsigned char *) cur->end);if ((unsigned char *) cur <= (unsigned char *) p && (unsigned char *) p <= (unsigned char *) cur->end) {cur->quote--;if (cur->quote == 0) {if (cur == pool->head) {pool->head->last = (unsigned char *) pool + sizeof(struct mp_pool_s) + sizeof(struct mp_node_s);}else {cur->last = (unsigned char *) cur + sizeof(struct mp_node_s);}cur->failed = 0;pool->current = pool->head;}return;}}}
内存池测试//// Created by 68725 on 2022/7/26.//#include <stdlib.h>#include <stdio.h>#include <string.h>#define PAGE_SIZE 4096#define MP_ALIGNMENT 16#define mp_align(n, alignment) (((n)+(alignment-1)) & ~(alignment-1))#define mp_align_ptr(p, alignment) (void *)((((size_t)p)+(alignment-1)) & ~(alignment-1))//每4k一block结点struct mp_node_s {unsigned char *end;//块的结尾unsigned char *last;//使用到哪了struct mp_node_s *next;//链表int quote;//引用计数int failed;//失效次数};struct mp_large_s {struct mp_large_s *next;//链表int size;//alloc的大小void *alloc;//大块内存的起始地址};struct mp_pool_s {struct mp_large_s *large;struct mp_node_s *head;struct mp_node_s *current;};struct mp_pool_s *mp_create_pool(size_t size);void mp_destroy_pool(struct mp_pool_s *pool);void *mp_malloc(struct mp_pool_s *pool, size_t size);void *mp_calloc(struct mp_pool_s *pool, size_t size);void mp_free(struct mp_pool_s *pool, void *p);void mp_reset_pool(struct mp_pool_s *pool);void monitor_mp_poll(struct mp_pool_s *pool, char *tk);void mp_reset_pool(struct mp_pool_s *pool) {struct mp_node_s *cur;struct mp_large_s *large;for (large = pool->large; large; large = large->next) {if (large->alloc) {free(large->alloc);}}pool->large = NULL;pool->current = pool->head;for (cur = pool->head; cur; cur = cur->next) {cur->last = (unsigned char *) cur + sizeof(struct mp_node_s);cur->failed = 0;cur->quote = 0;}}//创建内存池struct mp_pool_s *mp_create_pool(size_t size) {struct mp_pool_s *pool;if (size < PAGE_SIZE || size % PAGE_SIZE != 0) {size = PAGE_SIZE;}//分配4k以上不用malloc,用posix_memalign/*int posix_memalign (void **memptr, size_t alignment, size_t size);*/int ret = posix_memalign((void **) &pool, MP_ALIGNMENT, size); //4K + mp_pool_sif (ret) {return NULL;}pool->large = NULL;pool->current = pool->head = (unsigned char *) pool + sizeof(struct mp_pool_s);pool->head->last = (unsigned char *) pool + sizeof(struct mp_pool_s) + sizeof(struct mp_node_s);pool->head->end = (unsigned char *) pool + PAGE_SIZE;pool->head->failed = 0;return pool;}//销毁内存池void mp_destroy_pool(struct mp_pool_s *pool) {struct mp_large_s *large;for (large = pool->large; large; large = large->next) {if (large->alloc) {free(large->alloc);}}struct mp_node_s *cur, *next;cur = pool->head->next;while (cur) {next = cur->next;free(cur);cur = next;}free(pool);}//size>4kvoid *mp_malloc_large(struct mp_pool_s *pool, size_t size) {unsigned char *big_addr;int ret = posix_memalign((void **) &big_addr, MP_ALIGNMENT, size); //sizeif (ret) {return NULL;}struct mp_large_s *large;//released struct large resumeint n = 0;for (large = pool->large; large; large = large->next) {if (large->alloc == NULL) {large->size = size;large->alloc = big_addr;return big_addr;}if (n++ > 3) {break;// 为了避免过多的遍历,限制次数}}large = mp_malloc(pool, sizeof(struct mp_large_s));if (large == NULL) {free(big_addr);return NULL;}large->size = size;large->alloc = big_addr;large->next = pool->large;pool->large = large;return big_addr;}//new block 4kvoid *mp_malloc_block(struct mp_pool_s *pool, size_t size) {unsigned char *block;int ret = posix_memalign((void **) &block, MP_ALIGNMENT, PAGE_SIZE); //4Kif (ret) {return NULL;}struct mp_node_s *new_node = (struct mp_node_s *) block;new_node->end = block + PAGE_SIZE;new_node->next = NULL;unsigned char *ret_addr = mp_align_ptr(block + sizeof(struct mp_node_s), MP_ALIGNMENT);new_node->last = ret_addr + size;new_node->quote++;struct mp_node_s *current = pool->current;struct mp_node_s *cur = NULL;for (cur = current; cur->next; cur = cur->next) {if (cur->failed++ > 4) {current = cur->next;}}//now cur = last nodecur->next = new_node;pool->current = current;return ret_addr;}//分配内存void *mp_malloc(struct mp_pool_s *pool, size_t size) {if (size <= 0) {return NULL;}if (size > PAGE_SIZE - sizeof(struct mp_node_s)) {//largereturn mp_malloc_large(pool, size);}else {//smallunsigned char *mem_addr = NULL;struct mp_node_s *cur = NULL;cur = pool->current;while (cur) {mem_addr = mp_align_ptr(cur->last, MP_ALIGNMENT);if (cur->end - mem_addr >= size) {cur->quote++;//引用+1cur->last = mem_addr + size;return mem_addr;}else {cur = cur->next;}}return mp_malloc_block(pool, size);// open new space}}void *mp_calloc(struct mp_pool_s *pool, size_t size) {void *mem_addr = mp_malloc(pool, size);if (mem_addr) {memset(mem_addr, 0, size);}return mem_addr;}//释放内存void mp_free(struct mp_pool_s *pool, void *p) {struct mp_large_s *large;for (large = pool->large; large; large = large->next) {//大块if (p == large->alloc) {free(large->alloc);large->size = 0;large->alloc = NULL;return;}}//小块 引用-1struct mp_node_s *cur = NULL;for (cur = pool->head; cur; cur = cur->next) {//printf("cur:%pp:%pend:%pn", (unsigned char *) cur, (unsigned char *) p, (unsigned char *) cur->end);if ((unsigned char *) cur <= (unsigned char *) p && (unsigned char *) p <= (unsigned char *) cur->end) {cur->quote--;if (cur->quote == 0) {if (cur == pool->head) {pool->head->last = (unsigned char *) pool + sizeof(struct mp_pool_s) + sizeof(struct mp_node_s);}else {cur->last = (unsigned char *) cur + sizeof(struct mp_node_s);}cur->failed = 0;pool->current = pool->head;}return;}}}void monitor_mp_poll(struct mp_pool_s *pool, char *tk) {printf("rnrn------start monitor poll------%srnrn", tk);struct mp_node_s *head = NULL;int i = 0;for (head = pool->head; head; head = head->next) {i++;if (pool->current == head) {printf("current==>第%d块n", i);}if (i == 1) {printf("第%02d块small block已使用:%4ld剩余空间:%4ld引用:%4dfailed:%4dn", i,(unsigned char *) head->last - (unsigned char *) pool,head->end - head->last, head->quote, head->failed);}else {printf("第%02d块small block已使用:%4ld剩余空间:%4ld引用:%4dfailed:%4dn", i,(unsigned char *) head->last - (unsigned char *) head,head->end - head->last, head->quote, head->failed);}}struct mp_large_s *large;i = 0;for (large = pool->large; large; large = large->next) {i++;if (large->alloc != NULL) {printf("第%d块large blocksize=%dn", i, large->size);}}printf("rnrn------stop monitor poll------rnrn");}int main() {struct mp_pool_s *p = mp_create_pool(PAGE_SIZE);monitor_mp_poll(p, "create memory pool");#if 0printf("mp_align(5, %d): %d, mp_align(17, %d): %dn", MP_ALIGNMENT, mp_align(5, MP_ALIGNMENT), MP_ALIGNMENT,mp_align(17, MP_ALIGNMENT));printf("mp_align_ptr(p->current, %d): %p, p->current: %pn", MP_ALIGNMENT, mp_align_ptr(p->current, MP_ALIGNMENT),p->current);#endifvoid *mp[30];int i;for (i = 0; i < 30; i++) {mp[i] = mp_malloc(p, 512);}monitor_mp_poll(p, "申请512字节30个");for (i = 0; i < 30; i++) {mp_free(p, mp[i]);}monitor_mp_poll(p, "销毁512字节30个");int j;for (i = 0; i < 50; i++) {char *pp = mp_calloc(p, 32);for (j = 0; j < 32; j++) {if (pp[j]) {printf("calloc wrongn");exit(-1);}}}monitor_mp_poll(p, "申请32字节50个");for (i = 0; i < 50; i++) {char *pp = mp_malloc(p, 3);}monitor_mp_poll(p, "申请3字节50个");void *pp[10];for (i = 0; i < 10; i++) {pp[i] = mp_malloc(p, 5120);}monitor_mp_poll(p, "申请大内存5120字节10个");for (i = 0; i < 10; i++) {mp_free(p, pp[i]);}monitor_mp_poll(p, "销毁大内存5120字节10个");mp_reset_pool(p);monitor_mp_poll(p, "reset pool");for (i = 0; i < 100; i++) {void *s = mp_malloc(p, 256);}monitor_mp_poll(p, "申请256字节100个");mp_destroy_pool(p);return 0;}
推荐阅读
- 带你搞懂符号执行的前世今生与最近技术
- 跑路鸟为什么被称作“沙漠地带的小丑”
- 带状疱疹会传染怎么办 带状疱疹会传染吗
- 没带身份证还能坐火车吗 没有身份证可以坐高铁吗
- iOS|iOS15.6带来新功能:和苹果家庭“垃圾邀请”说拜拜
- 乙肝病毒携带者是怎么传播的 乙肝病毒携带者会传染吗
- 翡翠|翡翠与二次元的结合,唤起一代人的记忆……
- 火车带酒规定2019 火车上可以带多少白酒 火车上能带酒吗
- 吐出痰像烂肉带血怎么办
- 骑自行车健身的误区有哪些? 骑自行车锻炼带来的三大效应