Allocator

  1. operator new()和malloc()
  2. allocator的具体实现
  3. GUN C 2.9 -allocator
  4. 总结
    1. std::allocator分配器
    2. std::alloc(gun_cxx::pool_alloc)
      1. STL的两级分配器

operator new()和malloc()

  • operator new会调用malloc
    • 使用malloc进行分配的时候不光会分配相应空间,还会生成一些overhead

allocator的具体实现

  • VC的allocator只是以operator newoperator delete来实现用于内存分配的allocate()和用于回收内存的deallocate()
    • 没有任何特殊设计
  • BC++的allocator只是以operator newoperator delete来实现用于内存分配的allocate()和用于回收内存的deallocate()
    • 没有任何特殊设计
  • GCC的标准allocator只是以operator newoperator delete来实现用于内存分配的allocate()和用于回收内存的deallocate()
    • 没有任何特殊设计
    • GUN C没有使用这个空间分配器
//vc6的空间分配器的实现
class allocator{
//...
    pointer allocate(size_type _N,const void*)
    {
        //用allocate分配内存的时候,会调用_Allocate()
        return (_Allocate((difference_type)_N,(pointer)0));
    }
    pointer deallocate(void _FARQ *_P,size_type)
    {
        //operator delete会调用c的free()
        operator delete(_P);
    }
};
//...
template<class _Ty> inline
_Ty _FARQ *_Allocate(_PDFT _N,_Ty _FARQ *)
{
    if(_N < 0) _N = 0;
    //可以看到_Allocate()函数会调用operator new()函数,而operator new就会调用malloc函数
    return ((_Ty _FARQ *)operator new((_SIZT)_N * sizeof(_Ty)));
}
// 直接使用allocators来分配和回收空间,需要指定大小,非常难用
int *p = allocator<int>().allocate(512,(int *)0);
allocate<int>().deallocate(p,512);

GUN C 2.9 -allocator

//GUN C中没有使用标准定义的allocator,而是使用的alloc,头文件在<stl_alloc.h>
template <class T,class Alloc = alloc>
class vecotor{
//...
};
  • 对于一般情况上,因为malloc申请的内存大小不一定,所以用malloc申请的内存单元需要记录空间大小。
  • 但是在容器中,因为容器中的元素大小都是一样的,每次还是用malloc进行分配,将会导致内存空间的浪费。

  • stl中的alloc维护了16条链表,每一条链表维护某个固定大小的区块,单向链表。(第i条链表维护$8*(i+1)大小的区块$)
    • 对于需要分配的内存区块,会按照8的倍数然后去找对应的大小的链表去申请。(例如申请50byte就会找第6条链表)
    • 对于初始化,每条链表会一次性申请一大块内存,然后进行切分。

总结

std::allocator分配器

  • SGI标准的空间分配器,它只对operator new和operator delete进行简单封装,运行效率较差。

std::alloc(gun_cxx::pool_alloc)

  • 由三部分组成
    • stl_constrcut.h定义了全局函数constrcutdestroy负责对象的构造和析构
    • stl_alloc.h定义了一、二级空间配置器
    • stl_uninitialized定义了全局函数,用来填充或复制大块内存数据

STL的两级分配器

  • 第一级直接用malloc和free
  • 第二级在 < 128b的时候使用内存池,在大于128b的时候调用第一级分配器