详解c语言实现的内存池(适用于两个线程、不加锁、效率高)
作者:yanghehuanglu
目的:
设计一个内存池,要求效率比系统调用的效率要高(测试1万次),同时支持一个线程申请,另外一个线程释放。
设计思路:
因为涉及到两个线程的申请和释放,前期考虑加锁的方式来实现,但是加锁后效率比系统调用的效率还要低,没有什么意义。所以当前的设计思路是这样的:
1,用一个单向链表来维护内存池
2,用一个[3][101]的二维数组存储待释放的内存的指针。每行的第一元素表示该行是否填满了,之后的每个元素存储的是待释放内存的指针。
3,每次释放内存的时候并没有真正的释放,只是将内存的指针填入上述数组。待填满这一行后,将该行的第一个元素置为1。
4,在申请内存时候遍历这3行的第一个元素,看是否为1,如果为1,则将该行的指针全部释放,并memset改行。
这样真正的申请和释放都是在一个线程的,并且两个线程分别操作数组的不同行,不用加锁。
线程池源码:
memory_pool.h代码:
#ifndef _MEMORY_POOL_H_ #define _MEMORY_POOL_H_ #define MP_ALIGNMENT 64 // 内存对齐字节数,按照32个字节进行字节对齐 #define BLOCK_MEM_LEN 128 // 内存块中申请内存的大小 #define FIRST_DIMENSION 3 // 待释放数组第一维 // 内存块结构 struct mp_block_s { struct mp_block_s *next; // 后向指针 char data[BLOCK_MEM_LEN]; }; // 内存池结构 struct mp_pool_s { struct mp_block_s *idle; // 空闲的块 // 待释放的指针地址数组,数组的第二维的第一个是标志位,表示是否已写满 long to_be_released[FIRST_DIMENSION][101]; // 下一个存放待释放的指针的索引 int release_index; }; struct mp_pool_s *mp_create_pool(size_t size); void mp_free_pool(struct mp_pool_s *pool); struct mp_block_s *mp_alloc(struct mp_pool_s *pool); void mp_free(struct mp_pool_s *pool, struct mp_block_s *block); void statistics(struct mp_pool_s *pool); #endif
memory_pool.c代码
#include <stdlib.h> #include <stdio.h> #include <string.h> #include <unistd.h> #include <fcntl.h> #include "memory_pool.h" void poll_for_release(struct mp_pool_s *pool); void release_mem_block(struct mp_pool_s *pool, struct mp_block_s *block); void statistics(struct mp_pool_s *pool); /************************************************************************************************************************ * 函数功能:创建内存池 * 参数说明: size ------------ 创建内存块的个数 * 返 回 值: 创建的内存池的指针 ************************************************************************************************************************/ struct mp_pool_s *mp_create_pool(size_t size) { struct mp_pool_s *pool; int ret = posix_memalign((void **)&pool, MP_ALIGNMENT, sizeof(struct mp_pool_s) + sizeof(struct mp_block_s) * size); if (ret) { return NULL; } memset(pool, 0, sizeof(struct mp_pool_s) + sizeof(struct mp_block_s) * size); struct mp_block_s * block = (struct mp_block_s *)((char *)pool + sizeof(struct mp_pool_s)); pool->idle = block; block->next = NULL; struct mp_block_s * tmp = block; for (int i = 1; i < size; i++) { block = (struct mp_block_s *)((char *)pool + sizeof(struct mp_pool_s) + sizeof(struct mp_block_s) * i); tmp->next = block; block->next = NULL; tmp = block; } // 初始化待释放内存数组 memset(pool->to_be_released, 0, FIRST_DIMENSION*101*(sizeof(long))); pool->release_index = 1; return pool; } /************************************************************************************************************************ * 函数功能:释放内存池 * 参数说明: size ------------ 创建内存块的个数 * 返 回 值: 创建的内存池的指针 ************************************************************************************************************************/ void mp_free_pool(struct mp_pool_s *pool) { // statistics(pool); free(pool); } /************************************************************************************************************************ * 函数功能:申请内存 * 参数说明: pool ------------ 内存池指针 * 返 回 值: 无 ************************************************************************************************************************/ struct mp_block_s *mp_alloc(struct mp_pool_s *pool) { if (!pool->idle) { printf("mem is null\n"); return NULL; } // 从idle链删除,删除首节点 struct mp_block_s *block = pool->idle; pool->idle = block->next; // 检查是否有需要释放的内存 poll_for_release(pool); return block; } /************************************************************************************************************************ * 函数功能:释放内存 * 参数说明: pool ------------ 内存池指针 * 返 回 值: 无 ************************************************************************************************************************/ void release_mem_block(struct mp_pool_s *pool, struct mp_block_s *block) { // 加入到idle链 if (pool->idle) { block->next = pool->idle; pool->idle = block; } else { pool->idle = block; pool->idle->next = NULL; } } /************************************************************************************************************************ * 函数功能:并没有真正的释放,只是将当前的内存块的地址添加到待释放数组 * 参数说明: pool ------------ 内存池指针 * 返 回 值: 无 ************************************************************************************************************************/ void mp_free(struct mp_pool_s *pool, struct mp_block_s *block) { // 数组的第一维 int first_dimension = pool->release_index / 101; // 数组的第二维 int second_dimension = pool->release_index % 101; pool->to_be_released[first_dimension][second_dimension] = (long)block; if (second_dimension == 100) { // 标志置为1表示这行满了 pool->to_be_released[first_dimension][0] = 1; pool->release_index = pool->release_index + 2; } else { pool->release_index++; } // 如果记录到最后一个了就要从第一个开始记录 if (pool->release_index == (FIRST_DIMENSION * 101 + 1)) { pool->release_index = 1; } } /************************************************************************************************************************ * 函数功能:遍历待释放数组,看是否需要真正释放内存。 * 参数说明: pool ------------ 内存池指针 * 返 回 值: 无 ************************************************************************************************************************/ void poll_for_release(struct mp_pool_s *pool) { for (int i = 0; i < FIRST_DIMENSION; i++) { if (pool->to_be_released[i][0]) { for (int j = 0; j < 100; j++) { release_mem_block(pool, (struct mp_block_s *)(pool->to_be_released[i][j + 1])); } memset(pool->to_be_released[i], 0, 101 * sizeof(long)); } } } /************************************************************************************************************************ * 函数功能:统计idle和allocated的数量 * 参数说明: pool ------------ 内存池指针 * 返 回 值: 无 ************************************************************************************************************************/ void statistics(struct mp_pool_s *pool) { int idle = 0; struct mp_block_s *block = pool->idle; while(block) { // printf("statistics, idle, block = %p, block->next = %p\n", block, block->next); block = block->next; idle++; } printf("idle = %d\n", idle); for (int i = 0; i < FIRST_DIMENSION; i++) { for (int j = 0; j < 101; j++) { printf("%p, ", (void*)(pool->to_be_released[i][j])); } printf("\n"); } }
测试代码:
memory_pool_test.c 代码:
#include <stdlib.h> #include <stdio.h> #include <string.h> #include <unistd.h> #include <fcntl.h> #include <time.h> #include "memory_pool.h" int timespec_minus(struct timespec *a, struct timespec *b) { return (a->tv_sec - b->tv_sec) * 1000000 + (int)((a->tv_nsec - b->tv_nsec)/1000); } int main(int argc, char *argv[]) { int size = 1024; printf("size = %d\n", size); struct mp_pool_s *pool = mp_create_pool(size); printf("mp_create_pool over\n"); // statistics(pool); struct timespec before, after; clock_gettime(CLOCK_MONOTONIC, &before); struct mp_block_s *block = NULL; int i = 0; for (i = 0;i < 10000;i ++) { block = mp_alloc(pool); mp_free(pool, block); // if (i % 100 == 0) { // statistics(pool); // } } // statistics(pool); clock_gettime(CLOCK_MONOTONIC, &after); int delay = timespec_minus(&after, &before); printf("mempool malloc 10000 times : %d microsecond\n", delay); mp_free_pool(pool); clock_gettime(CLOCK_MONOTONIC, &before); char * p = NULL; for (i = 0;i < 10000;i ++) { p = malloc(128); free(p); } clock_gettime(CLOCK_MONOTONIC, &after); delay = timespec_minus(&after, &before); printf("system malloc 10000 times : %d microsecond\n", delay); return 0; }
测试结果:
(base) root@liyan-virtual-machine:/home/zhangmeng/test/memory_pool# make
cc os_mutex.c memory_pool.c memory_pool_test.c -o memory_pool_test -lpthread
(base) root@liyan-virtual-machine:/home/zhangmeng/test/memory_pool# ./memory_pool_test
size = 1024
mp_create_pool over
mempool malloc 10000 times : 154 microsecond
system malloc 10000 times : 366 microsecond
(base) root@liyan-virtual-machine:/home/zhangmeng/test/memory_pool# ./memory_pool_test
size = 1024
mp_create_pool over
mempool malloc 10000 times : 136 microsecond
system malloc 10000 times : 333 microsecond
(base) root@liyan-virtual-machine:/home/zhangmeng/test/memory_pool# ./memory_pool_test
size = 1024
mp_create_pool over
mempool malloc 10000 times : 163 microsecond
system malloc 10000 times : 333 microsecond
(base) root@liyan-virtual-machine:/home/zhangmeng/test/memory_pool# ./memory_pool_test
size = 1024
mp_create_pool over
mempool malloc 10000 times : 136 microsecond
system malloc 10000 times : 334 microsecond
(base) root@liyan-virtual-machine:/home/zhangmeng/test/memory_pool# ./memory_pool_test
size = 1024
mp_create_pool over
mempool malloc 10000 times : 154 microsecond
system malloc 10000 times : 349 microsecond
(base) root@liyan-virtual-machine:/home/zhangmeng/test/memory_pool# ./memory_pool_test
size = 1024
mp_create_pool over
mempool malloc 10000 times : 298 microsecond
system malloc 10000 times : 351 microsecond
(base) root@liyan-virtual-machine:/home/zhangmeng/test/memory_pool# ./memory_pool_test
size = 1024
mp_create_pool over
mempool malloc 10000 times : 143 microsecond
system malloc 10000 times : 342 microsecond
(base) root@liyan-virtual-machine:/home/zhangmeng/test/memory_pool# ./memory_pool_test
size = 1024
mp_create_pool over
mempool malloc 10000 times : 139 microsecond
system malloc 10000 times : 333 microsecond
(base) root@liyan-virtual-machine:/home/zhangmeng/test/memory_pool# ./memory_pool_test
size = 1024
mp_create_pool over
mempool malloc 10000 times : 164 microsecond
system malloc 10000 times : 350 microsecond
(base) root@liyan-virtual-machine:/home/zhangmeng/test/memory_pool# ./memory_pool_test
size = 1024
mp_create_pool over
mempool malloc 10000 times : 191 microsecond
system malloc 10000 times : 333 microsecond
(base) root@liyan-virtual-machine:/home/zhangmeng/test/memory_pool# ./memory_pool_test
size = 1024
mp_create_pool over
mempool malloc 10000 times : 308 microsecond
system malloc 10000 times : 542 microsecond
(base) root@liyan-virtual-machine:/home/zhangmeng/test/memory_pool# ./memory_pool_test
size = 1024
mp_create_pool over
mempool malloc 10000 times : 178 microsecond
system malloc 10000 times : 355 microsecond
(base) root@liyan-virtual-machine:/home/zhangmeng/test/memory_pool# ./memory_pool_test
size = 1024
mp_create_pool over
mempool malloc 10000 times : 304 microsecond
system malloc 10000 times : 349 microsecond
(base) root@liyan-virtual-machine:/home/zhangmeng/test/memory_pool# ./memory_pool_test
size = 1024
mp_create_pool over
mempool malloc 10000 times : 327 microsecond
system malloc 10000 times : 453 microsecond
(base) root@liyan-virtual-machine:/home/zhangmeng/test/memory_pool# ./memory_pool_test
size = 1024
mp_create_pool over
mempool malloc 10000 times : 213 microsecond
system malloc 10000 times : 333 microsecond
(base) root@liyan-virtual-machine:/home/zhangmeng/test/memory_pool# ./memory_pool_test
size = 1024
mp_create_pool over
mempool malloc 10000 times : 306 microsecond
system malloc 10000 times : 578 microsecond
(base) root@liyan-virtual-machine:/home/zhangmeng/test/memory_pool# ./memory_pool_test
size = 1024
mp_create_pool over
mempool malloc 10000 times : 160 microsecond
system malloc 10000 times : 333 microsecond
(base) root@liyan-virtual-machine:/home/zhangmeng/test/memory_pool# ./memory_pool_test
size = 1024
mp_create_pool over
mempool malloc 10000 times : 334 microsecond
system malloc 10000 times : 355 microsecond
(base) root@liyan-virtual-machine:/home/zhangmeng/test/memory_pool# ./memory_pool_test
size = 1024
mp_create_pool over
mempool malloc 10000 times : 189 microsecond
system malloc 10000 times : 333 microsecond
(base) root@liyan-virtual-machine:/home/zhangmeng/test/memory_pool# ./memory_pool_test
size = 1024
mp_create_pool over
mempool malloc 10000 times : 204 microsecond
system malloc 10000 times : 349 microsecond
(base) root@liyan-virtual-machine:/home/zhangmeng/test/memory_pool# ./memory_pool_test
size = 1024
mp_create_pool over
mempool malloc 10000 times : 384 microsecond
system malloc 10000 times : 333 microsecond
(base) root@liyan-virtual-machine:/home/zhangmeng/test/memory_pool# ./memory_pool_test
size = 1024
mp_create_pool over
mempool malloc 10000 times : 295 microsecond
system malloc 10000 times : 333 microsecond
(base) root@liyan-virtual-machine:/home/zhangmeng/test/memory_pool# ./memory_pool_test
size = 1024
mp_create_pool over
mempool malloc 10000 times : 306 microsecond
system malloc 10000 times : 509 microsecond
(base) root@liyan-virtual-machine:/home/zhangmeng/test/memory_pool# ./memory_pool_test
size = 1024
mp_create_pool over
mempool malloc 10000 times : 151 microsecond
system malloc 10000 times : 333 microsecond
(base) root@liyan-virtual-machine:/home/zhangmeng/test/memory_pool# ./memory_pool_test
size = 1024
mp_create_pool over
mempool malloc 10000 times : 189 microsecond
system malloc 10000 times : 364 microsecond
(base) root@liyan-virtual-machine:/home/zhangmeng/test/memory_pool# ./memory_pool_test
size = 1024
mp_create_pool over
mempool malloc 10000 times : 146 microsecond
system malloc 10000 times : 332 microsecond
(base) root@liyan-virtual-machine:/home/zhangmeng/test/memory_pool# ./memory_pool_test
size = 1024
mp_create_pool over
mempool malloc 10000 times : 190 microsecond
system malloc 10000 times : 337 microsecond
(base) root@liyan-virtual-machine:/home/zhangmeng/test/memory_pool# ./memory_pool_test
size = 1024
mp_create_pool over
mempool malloc 10000 times : 159 microsecond
system malloc 10000 times : 333 microsecond
(base) root@liyan-virtual-machine:/home/zhangmeng/test/memory_pool# ./memory_pool_test
size = 1024
mp_create_pool over
mempool malloc 10000 times : 204 microsecond
system malloc 10000 times : 341 microsecond
(base) root@liyan-virtual-machine:/home/zhangmeng/test/memory_pool# ./memory_pool_test
size = 1024
mp_create_pool over
mempool malloc 10000 times : 188 microsecond
system malloc 10000 times : 333 microsecond
(base) root@liyan-virtual-machine:/home/zhangmeng/test/memory_pool# ./memory_pool_test
size = 1024
mp_create_pool over
mempool malloc 10000 times : 213 microsecond
system malloc 10000 times : 341 microsecond
(base) root@liyan-virtual-machine:/home/zhangmeng/test/memory_pool# ./memory_pool_test
size = 1024
mp_create_pool over
mempool malloc 10000 times : 138 microsecond
system malloc 10000 times : 342 microsecond
(base) root@liyan-virtual-machine:/home/zhangmeng/test/memory_pool# ./memory_pool_test
size = 1024
mp_create_pool over
mempool malloc 10000 times : 146 microsecond
system malloc 10000 times : 333 microsecond
(base) root@liyan-virtual-machine:/home/zhangmeng/test/memory_pool# ./memory_pool_test
size = 1024
mp_create_pool over
mempool malloc 10000 times : 324 microsecond
system malloc 10000 times : 550 microsecond
(base) root@liyan-virtual-machine:/home/zhangmeng/test/memory_pool# ./memory_pool_test
size = 1024
mp_create_pool over
mempool malloc 10000 times : 143 microsecond
system malloc 10000 times : 344 microsecond
(base) root@liyan-virtual-machine:/home/zhangmeng/test/memory_pool# ./memory_pool_test
size = 1024
mp_create_pool over
mempool malloc 10000 times : 278 microsecond
system malloc 10000 times : 333 microsecond
(base) root@liyan-virtual-machine:/home/zhangmeng/test/memory_pool# ./memory_pool_test
size = 1024
mp_create_pool over
mempool malloc 10000 times : 149 microsecond
system malloc 10000 times : 341 microsecond
(base) root@liyan-virtual-machine:/home/zhangmeng/test/memory_pool# ./memory_pool_test
size = 1024
mp_create_pool over
mempool malloc 10000 times : 146 microsecond
system malloc 10000 times : 336 microsecond
(base) root@liyan-virtual-machine:/home/zhangmeng/test/memory_pool# ./memory_pool_test
size = 1024
mp_create_pool over
mempool malloc 10000 times : 150 microsecond
system malloc 10000 times : 344 microsecond
(base) root@liyan-virtual-machine:/home/zhangmeng/test/memory_pool# ./memory_pool_test
size = 1024
mp_create_pool over
mempool malloc 10000 times : 324 microsecond
system malloc 10000 times : 369 microsecond
(base) root@liyan-virtual-machine:/home/zhangmeng/test/memory_pool# ./memory_pool_test
size = 1024
mp_create_pool over
mempool malloc 10000 times : 223 microsecond
system malloc 10000 times : 336 microsecond
(base) root@liyan-virtual-machine:/home/zhangmeng/test/memory_pool# ./memory_pool_test
size = 1024
mp_create_pool over
mempool malloc 10000 times : 208 microsecond
system malloc 10000 times : 335 microsecond
(base) root@liyan-virtual-machine:/home/zhangmeng/test/memory_pool# ./memory_pool_test
size = 1024
mp_create_pool over
mempool malloc 10000 times : 146 microsecond
system malloc 10000 times : 333 microsecond
(base) root@liyan-virtual-machine:/home/zhangmeng/test/memory_pool# ./memory_pool_test
size = 1024
mp_create_pool over
mempool malloc 10000 times : 151 microsecond
system malloc 10000 times : 333 microsecond
(base) root@liyan-virtual-machine:/home/zhangmeng/test/memory_pool#
测试结论:
1,能够解决两个线程互斥的问题
2,用自己实现的内存池测试10000次的平均时间是:207微秒,用系统malloc/free测试10000次的平均时间是:377微秒,时间约为系统调用时间的54%。而且解决了碎片问题。
备注:
一般设计的内存池都是有局限性的,只能适用于某个场景,当前这个内存池只适用于一个线程申请,另外一个线程释放的场景。
到此这篇关于c语言实现的内存池(适用于两个线程、不加锁、效率高)的文章就介绍到这了,更多相关c语言内存池内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!