自实现C语言的内存池

前言

具体什么是内存池,不说了。我也是闲来无聊,自己实现一个内存池,也比较简单。

设计思路

我们采用C语言实现,所以,需要实现一些简单的容器。比如单链表。
内存池的总体设计
总体大概设计思路示意图如上所示。
一个数组(或者向量(我们把原始的C语言数组,称之为数组,把类似的在堆空间中申请来的连续线线性空间称之为向量)),每一个节点是一个链表,每个链表里面挂着元素,元素的data指针便是我们内存池里面放的内存指针。

详细思路

第一:纲领数组我们按照索引,最小比如64,128,256 这样预先定义好。到了足够大之后,比如4k,我们便采用比如1k的颗粒度上涨。
第二:当申请的内存不足档位量的时候,我们便直接采用档位量。
第三:链表的策略

  1. 每个节点内部,我们维护两个链表。
    0号链表,我们作为idle 空闲链表,申请的内存被释放之后,都存到这个数组里面。
    1号链表,我们作为busy链表,我们存到这个里面。
    这种做法,就是每次申请,都是0(1)复杂度,但是释放较为复杂,需要遍历busy链表,从中remove,然后插入回idle(push head 插入)。
    所以申请 O(1);释放 O(n),n为当前该节点下的busy的个数。
  2. 每个纲领节点,一个链表,其中分为idle以及busy部分。前段idle,后段busy。为了复杂度尽量的低,所以,每次申请释放,我们尽量保持从头拿,然后插入尾。至于释放,需要遍历,单链表,那就只能从头部遍历,那么复杂度相对较高,(前面一堆是空的idle)。要么采用双链表,从尾部busy遍历。复杂度跟1一致,但是,内存使用多了一个prev指针。
  3. 还有一种,复杂度比较低,内存占用也会少一些,就是,每次申请出去的,我们不记录,就从idle里面拿出去,释放的时候,再插入进来。这种实现最简单,并且,复杂度最低。

第四:内存的申请方式。是整体采用一大块内存,然后分摊的方式,分到各个链表的data中。要么离散式,随用随申请,到一定数量之后,要么OOM报错,要么,一直这样,达到一定数量之后,会被有申请的被释放回来,就可以达到复用了。

实现

目录结构

目录结构
项目支持windows以及linux系统。
不写make file了,回头单独开一遍博客,说明gyp的用法。

源码

FC.h

#ifndef __FC__H__
#define __FC__H__

#if defined _WIN32 || defined _WIN64
#  define	FC_WIN
#  define   FCAPI	__stdcall
#elif defined __linux__
#  define	FC_LINUX
#  define   FCAPI	
#endif

#endif // !__FC__H__

list.h && list.c

#ifndef __FC_LIST_LIST_H__
#define __FC_LIST_LIST_H__

#include "FC.h"
#include <stdio.h>
#include <stdlib.h>
#include "../FCMemPool.h"

#ifdef FC_WIN
#   pragma pack(1)
	struct FC_Node_T
	{
		// 记录 lvl,
		struct FC_Node_T *	next;
		int		lvl;
		// 标记着该档位的大小,方便快速定位到对应的数组索引 
		char	data[0];
	};
#   pragma pack()
#else
	struct __attribute__((__packed__)) FC_Node_T
	{
		// 记录 lvl,
		struct FC_Node_T *	next;
		int		lvl;
		// 标记着该档位的大小,方便快速定位到对应的数组索引 
		char	data[0];
	};
#endif // !FC_WIN

typedef struct FC_Node_T FC_Node;

typedef struct FC_List_T
{
	FC_Node*	head;
	int			available;	// 当前可用的数量
	int			total_size;	// 总体申请的数量
} FC_List;

#define FC_ListNode(ptr)				(FC_Node*)((ptr) - sizeof(FC_Node))

#define FC_ListAvailable(list)			(((FC_List*)(list))->available)
#define FC_ListSize(list)				((FC_List*)(list)->total_size)

#define FC_ListIncAvailable(list)		(((FC_List*)(list))->available ++)
#define FC_ListDecAvailable(list)		(((FC_List*)(list))->available --)
#define FC_ListIncSize(list)			(((FC_List*)(list))->total_size ++)
#define FC_ListDecSize(list)			(((FC_List*)(list))->total_size --)

FC_Node* FC_NodeCreate(FC_size_t size, int lvl);

FC_List* FC_ListCreate();

void FC_ListDestroy(FC_List* list);

void FC_ListAddHead(FC_List* list, FC_Node* node);

FC_Node* FC_ListPopHead(FC_List* list);

#endif // !__FC_LIST_LIST_H__

list.c

#include "list.h"

FC_Node * FC_NodeCreate(FC_size_t size, int lvl)
{
	void* data = NULL;

	FC_Node* node = (FC_Node*)malloc(sizeof(FC_Node) + size);
	if (node == NULL)
	{
		return NULL;
	}
	node->lvl = lvl;
	node->next = NULL;

	return node;
}

FC_List * FC_ListCreate()
{
	FC_List * list = (FC_List*)malloc(sizeof(FC_List));
	if (list == NULL)
	{
		return NULL;
	}
	list->available = 0;
	list->total_size = 0;
	list->head = NULL;
	return list;
}

void FC_ListDestroy(FC_List * list)
{
	if (list == NULL)
	{
		return;
	}
	FC_Node* tmp = NULL;
	while (list->head)
	{
		tmp = list->head;
		list->head = list->head->next;
		free(tmp);
	}
	free(list);
	return ;
}

void FC_ListAddHead(FC_List * list, FC_Node * node)
{
	if (list == NULL || node == NULL)
	{
		return;
	}
	node->next = list->head;
	list->head = node;
}

FC_Node * FC_ListPopHead(FC_List * list)
{
	if (list == NULL)
	{
		return NULL;
	}
	FC_Node* node = list->head;
	if (list->head)
	{
		list->head = list->head->next;
	}
	if (node)
	{
		node->next = NULL;
	}
	return node;
}

FCMemPool.h

#ifndef __FC_MEM_MGR_H__
#define __FC_MEM_MGR_H__

#include "FC.h"
#include <stdio.h>
#include <stdlib.h>

#define MAX_COUNT_THREHOLD	(32)

typedef	size_t				FC_size_t;
typedef struct FC_List_T	FC_List;

typedef struct FCMemPool_T
{
	FC_List*	arr[8];
} FCMemPool;

FCMemPool* FC_MemPoolAlloc();

void FC_MemPoolDestroy(void* pool);

void* FC_Malloc(void* pool, FC_size_t size);

void FC_Free(void* pool, void* ptr);

#endif // !__FC_MEM_MGR_H__

FCMemPool.c

#include "FCMemPool.h"
#include "list/list.h"


enum
{
	FC_P_LVL_BASE = (FC_size_t)64,
	FC_P_LVL_0 = (FC_size_t)(FC_P_LVL_BASE << 0),
	FC_P_LVL_1 = (FC_size_t)(FC_P_LVL_BASE << 1),
	FC_P_LVL_2 = (FC_size_t)(FC_P_LVL_BASE << 2),
	FC_P_LVL_3 = (FC_size_t)(FC_P_LVL_BASE << 3),
	FC_P_LVL_4 = (FC_size_t)(FC_P_LVL_BASE << 4),
	FC_P_LVL_5 = (FC_size_t)(FC_P_LVL_BASE << 5),
	FC_P_LVL_6 = (FC_size_t)(FC_P_LVL_BASE << 6),	// 4096
	FC_P_LVL_7 = (FC_size_t)(FC_P_LVL_BASE << 7),	// 8192
};

static FC_size_t get_size(int lvl)
{
	if (lvl >= 8 || lvl < 0)
	{
		return 0;
	}
	static FC_size_t size_arr[8] = {
		FC_P_LVL_0, FC_P_LVL_1, FC_P_LVL_2, FC_P_LVL_3,
		FC_P_LVL_4, FC_P_LVL_5, FC_P_LVL_6, FC_P_LVL_7};
	return size_arr[lvl];
}

static int get_level(FC_size_t size)
{
	if (size <= FC_P_LVL_0) { return 0; }
	if (size <= FC_P_LVL_1) { return 1; }
	if (size <= FC_P_LVL_2) { return 2; }
	if (size <= FC_P_LVL_3) { return 3; }
	if (size <= FC_P_LVL_4) { return 4; }
	if (size <= FC_P_LVL_5) { return 5; }
	if (size <= FC_P_LVL_6) { return 6; }
	if (size <= FC_P_LVL_7) { return 7; }
	return -1;
}

FCMemPool * FC_MemPoolAlloc()
{
	FCMemPool * pool = (FCMemPool*)malloc(sizeof(FCMemPool));
	int i = 0;
	for (; i < 8; i++)
	{
		pool->arr[i] = FC_ListCreate();
	}
	return pool;
}

void FC_MemPoolDestroy(void * pool)
{
	FCMemPool * p = (FCMemPool*)pool;
	int i = 0;
	for (; i < 8; i++)
	{
		FC_ListDestroy(p->arr[i]);
	}
	return;
}

void * FC_Malloc(void * pool, FC_size_t size)
{
	if (pool == NULL || size <= 0)
	{
		return NULL;
	}
	int lvl = get_level(size);
	if (lvl == -1)
	{
		return NULL;
	}
	FC_List* list = ((FCMemPool*)pool)->arr[lvl];
	FC_Node* node = NULL;
	if (list->available == 0)
	{
		node = FC_NodeCreate(get_size(lvl), lvl);
		if (node == NULL)
		{
			return NULL;
		}
		FC_ListIncSize(list);
	}
	else
	{
		node = FC_ListPopHead(list);
		if (node == NULL)
		{
			return NULL;
		}
		FC_ListDecAvailable(list);
	}
	return node->data;
}

void FC_Free(void * pool, void * ptr)
{
	if (pool == NULL || ptr == NULL)
	{
		return;
	}

	FC_Node * node = FC_ListNode((char*)ptr);
	FC_List * list = (FC_List*)(((FCMemPool*)pool)->arr[node->lvl]);
	FC_ListAddHead(list, node);
	FC_ListIncAvailable(list);
}

main.c

#include <stdio.h>
#include <stdlib.h>

#include "FC.h"
#include "FCMemPool/FCMemPool.h"


int main(int argc, char* argv[])
{
	FCMemPool * p = FC_MemPoolAlloc();

	char* bf = (char*)(FC_Malloc(p, 24));

	FC_Free(p, bf);

	FC_MemPoolDestroy(p);

	return 0;
}

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值