STL源码剖析(1)空间分配器

2022/7/27 14:25:18

本文主要是介绍STL源码剖析(1)空间分配器,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

配置器的接口

  • allocate:分配内存

  • deallocate:释放内存

  • construct:在已申请的内存上构造对象

  • destroy:析构对象

  • address:取某个对象的地址

  • const_address:常版本地址

  • max_size:返回可申请的最大空间

标准库的分配器

std::allocator,这个分配器类只是对原始的new和delete做了一层包装,效率很低不建议使用。

std::alloc:这个才是真正投入使用的

构造和析构

构造很容易,直接用placement new就行了

template<class T1, class T2>
inline void construct(T1 *p, const T2& value) {
    new (p) T1(value); // placement new,在以分配的内存上构造
}

析构就比较麻烦了,有好几个版本,这里看最简单的,直接调用析构函数析构

template<class T>
inline void deconstruct(T *pointer) {
    pointer->~T(); //调用析构
}

内存的申请与释放

这一块涉及到操作系统的一些知识。为了简单,我们不考虑多线程的各种同步问题。

最简单的内存分配,就是用使用new和delete,底层是c的malloc和free。但是,如果每次申请的内存都是很小一块,会导致内存碎片的问题。

STL设置了两级的分配器。如果分配的内存很大,那么就直接使用一级分配器。如果很小,就使用内存池,让二级分配器来分配内存。

一级分配器

一级分配器非常简单,主要功能如下

  • 用malloc分配内存
  • realloc重新调整大小
  • free释放内存
  • 提供函数指针,供用处处理内存不足的情况

二级分配器

二级分配器用来分配小于128k的内存,大于这个数的内存交给一级分配器完成。

二级分配器用内存池来维护一系列内存块。首先,分配器保存了一个freeList,这个freeList是一个链表数组,保存了8的倍数的内存块,并以链表维护。

解释一下,freeList的定义是这样的:void *freeList[16],其中freeList[0]保存一个链表,这个链表每个节点的大小都是8个字节,同理,freeList[1]保存一个节点为16字节大小的链表。那这样第16个就是保存128字节大小的内存块。

有个问题是链表的next指针,如果单独在每个节点中加个next,开销还是很大的。这里我们可以用union,当内存节点在freeList中的时候,就当作一个next指针。当该内存节点被申请后,就当作真实数据。

还有一个需要注意的是,我们会对申请的字节做一个8字节对齐(便于内存的分配)。比如我们申请2个字节,会自动对齐到8字节;申请15字节会对齐到16字节。

处理内存的工具

这是几个全局函数,在大规模内存上构造对象。

uninitialized_copy

// 将first和last之间的对象产生一个拷贝,并用于构造result到result+(last-frist)之间的内存。
uninitialized_copy(first, last, result);

uninitialized_fill

// 用T构造first到last之间的内存
uninitialized_fill(first, last, T);

uninitialized_fill_n

// 用T构造first到first + n之间的内存
uninitialized_fill_n(first, n, T);


这篇关于STL源码剖析(1)空间分配器的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!


扫一扫关注最新编程教程