最近在学习redis源码,想着光看不如自己动动手,于是写了个localRedis
如名字所示,这是个本地数据库,有着与redis类似的命令接口,但内部实现比较简单,只提取了一些主要逻辑
如有错误或不合理的地方,恳请指出!谢谢!
源码地址: https://github.com/BAN1993/localRedis
(这篇文章主要是内存池的实现,与redis关系不大~)
目的
做这个内存池主要目的是为了方便管理内存和减少内存碎片,但是效率会比new/delete低(这里只是简单测试结果)。
另外还有一个后面调试才发现的好处(适合学习,不适合用在项目中),可以在程序退出时打印忘记释放的内存。比如:
#include "base.h"
#include "mallocManager.h"
int main()
{
char* c = (char*)__new(1024);
sprintf(c,"hello word!");
LOG(c);
return 0;
}
最后编译运行会输出如下:
[main:8]hello word!
[~mallocManager:10]UNDELETE:filename=main.cpp,line=6
设计
这个内存池的核心思想是每次申请大块内存,然后拆分成N块小内存插入到空闲队列供后面取用。new时从空闲队列取,队列为空就继续申请大块内存;delete时将内存插回空闲队列。
流程
我们会将取用的内存大小向上调整为整数(2的倍数,8,16,32......2K,4K,8K),每种大小都会维护一个内存池。
比如想要取用一块char[5]的内存时,我们会返回一块8字节的内存:
①若相应池中空闲队列不为空,直接返回
②若相应池中空闲队列为空,先申请一块8K大小的内存,将它拆分成8192/8块,逐一插入空闲队列再返回其一
经过一段时间的取用后,内存使用情况可能如下:
可以看到目前只创建并使用了8,128,4K三种类型的内存池,其中8空闲还比较多;128已满,下次取用就会扩充;4K还有一块空闲。
若一次申请的内存大于8K,那么会直接申请相应大小的内存块并存到一个big列表中,释放时也是直接删除。
例子
#include "base.h"
#include "mallocManager.h"
class TestA
{
public:
TestA(int size)
{
size = size <= 0 ? 1 : size;
// m_p = new char[size];
// or
m_p = (char*)__new(size);
}
~TestA()
{
if(m_p)
{
// delete[] m_p;
// or
__delete(m_p);
}
m_p = nullptr;
}
private:
char* m_p;
};
int main()
{
__new_obj_1(TestA, p, 666);
// do something
// p->...
__delete_obj(TestA, p);
return 0;
}
实现源码见:https://github.com/BAN1993/localRedis
mallocPool.cpp/.h
mallocManager.cpp/.h