目的:
设计一个内存池,要求效率比系统调用的效率要高(测试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%。而且解决了碎片问题。
备注:
一般设计的内存池都是有局限性的,只能适用于某个场景,当前这个内存池只适用于一个线程申请,另外一个线程释放的场景。