首页 > 代码库 > 简单的静态分配器(C++

简单的静态分配器(C++

静态分配器,简单来说就是使用户能从静态内存区请求内存空间而非使用堆或者栈,和我们平时嫌堆栈太小或者从堆动态请求内存太慢而开了个大数组,然后使用这个数组的内存空间本质来讲没有什么区别,写这个代码是为了能更方便,更灵活,(更高效?)地来使用静态内存区。

以下是代码

https://github.com/Dadio44/Test/blob/master/Many_Test/Many_Test/StaticAllocatorBase.cpp

https://github.com/Dadio44/Test/blob/master/Many_Test/Many_Test/StaticAllocator.h

按类来组织,分为2层,StaticAllocatorBase ---> StaticAllocator

StaticAllocatorBase 最核心的代码都放置于此处,因为在使用内置类型作为模板参数时,可能会导致令人无法忽视的代码膨胀,所以使用 Effective C++ 里的建议,将与参数无关的代码写成了个独立的类。说一下一些优点,缺点,以及尚待改进的地方。

优点:

  静态请求内存(不能说完全静态,准确地说,得到内存这个过程,是在程序被操作系统载入时完成的,而且因为虚拟内存,内存分页这些东西,请求这些内存可能需要可观的运行时成本,这里说的静态,主要是指不需要 crt 的那些 malloc 、free ,这些函数为了能应付多种请求可能用了复杂的算法,避开他们的话感觉可以提高不少效率)

  分配以及请求内存只需要O(1)的时间,但是代价是需要O(n)(n大概是内存块的个数)

缺点 :

  无法处理小于 sizeof(decltype(sizeof(int))) 和不能整除 sizeof(decltype(sizeof(int))) 的类型,因为使用链表来保存,所以每个块需要保存一个 offset ,当然可以浪费点内存解决这个问题,当是我觉得得不偿失。 何况,这样还能强制要求内存对齐,那些关掉编译器优化并手动把内存大小写成奇怪奇数的人需要善意的提醒。

  浪费内存,因为是静态请求的内存,所以这些内存在程序结束之前是没法还给操作系统的。

类型和大小,哪个作为每个StaticAllocator的模板参数更好?可能有人会想,用大小做参数,内存不就可以重用了?比如 int* 与 char* 的大小一样,那么就可以让他们用同一个 StaticAllocator ,就提高了内存的利用率,但是这样有几个问题,首先,因为 StaticAllocator 利用了静态内存区,显然我们不能再 stack 和 heap 上创建它。于是,利用单例模式,返回局部静态变量是很好,甚至唯一的选择。但是,用户就不能根据类型来创建 Allocator 了。我一开始想,加多一个接口类模板,然后把那个模板的类型参数的size传给 StaticAllocator 

不就好了?假设那个接口叫T_Allocator考虑一下这种情况

auto pia = T_Allocator<int*,2>::getInsance();

auto pca = T_Allocator<char*,2>::getInsance();

auto p1 = pca->allocate();

auto p2 = pca->allocate();

pci->allocate()//内存不足

用户肯定会觉得奇怪。明明我一次pia都没请求过,突然就内存不足了。所以这个想法是不行的

后来又想,要不干脆不要类型参数,还是用 typesize 算了,反正只是用户用的时候要加个sizeof,还有获得指针要做一下类型转换而已嘛。

 

auto pia = T_Sta::StaticAllocator<sizeof(int*),2>::getInsance();

auto pca = T_Sta::StaticAllocator<sizeof(char*,)2>::getInsance();

int*    p1 = static_cast<int*>(pca->allocate());

char* p2 = static_cast<char*>(pca->allocate());

pci->allocate()//内存不足

这种代码应该不会让人感觉奇怪。创建两个小的分配器和创建一个大的,各方面想都是后者好。

于是代码就变成最后这个样子了。

这个是测试代码

 https://github.com/Dadio44/Test/blob/master/Many_Test/Many_Test/TestStaticAllocator.h

简单的静态分配器(C++