乐趣区

关于c++:C内存管理16GNU-C-对于-Allocator-的描述

当你将元素退出容器中,容器必须调配更多内存以保留这些元素,于是它们向其模板参数 Allocator 收回申请,该模板参数往往被另名为(aliased to)allocator_type。甚至你将 chars 增加到 string class 也是如此,因为 string 也算是一个正规 STL 容器。

template <class T, class Allocator=allocator<T>>
class vector;

template <class T, class Allocator=allocator<T>>
class list;

template <class T, class Allocator=allocator<T>>
class deque;

每个元素类型为 T 的容器(container-of-T)的 Allocator 模板参数默认为 allocator<T>。其接口只有大概 20 个 public 申明,包含嵌套的(nested)typedefs 和成员函数。最终要的两个函数是:

T *allocate(size_type n, const void *hint = 0);
void deallocate(T *p, size_type n);

n 指的是客户申请的元素个数,不是指空间数量(字节数)

这些空间都是通过调用 ::operator new 取得,但何时调用以及如许频繁调用,并无具体指定

最容易满足需要的做法就是每当容器须要内存就调用 operator new, 每当容器开释内存就调用 operator delete。这种做法比起调配大块内存并缓存(caching)而后徐徐小块应用当然慢,劣势则是能够在极大范畴的硬件和操作系统上无效运作

__gnu_cxx::new_allocator

实现出俭朴的 operator new 和 operator delete 语义

template<typename _Tp>
class new_allocator
{
    ....
    pointer allocate(size_type __n, const void*=0)
    {
        ....
        return static_cast<_Tp*>(operator new(__n * sizeof(_Tp)));
    }
    
    void deallocate(pointer __p, size_type)
    {::operator delete(__p);
    }
};

__gnu_cxx::malloc_allocator

template <typename _Tp>
class malloc_allocator
{pointer allocate(size_type __n, const void*=0)
    {
        ...
        pointer __ret = ...(std::malloc(__n * sizeof(_Tp)));
    }
    
    void deallocate(pointer __p, size_type)
    {std::free(...(__p));
    }
};

另一种做法就是应用智能型 allocator, 将调配所得的内存加以缓存 (cache、内存池)。这种额定机制能够数种模式出现:

能够是个 bitmap index, 用以索引至一个以 2 的指数倍成长的篮子(exponentially increasing power-of-two-sized buckets)

也能够是个相较之下比拟繁难的 fixed-size pooling cache

这里所说的 cache 被程序内的所有容器共享,而 operator new 和 operator delete 不常常被应用,这可带来速度上的劣势(底层 malloc 也是一个简单的内存池,速度劣势并不显著,次要是缩小了 cookie 的应用)。应用这类技巧的 allocators 包含:

__gnu_cxx::bitmap_allocator

一个高效能 allocator,应用 bit-map 追踪被应用和未被应用(used and unused)的内存块

__gnu_cxx::pool_allocator

__gnu_cxx::__mt_alloc

Class allocator 只领有 typedef, constructor 和 rebind 等成员。它继承子一个 high-speed extension allocators。也因而,所有调配和偿还(allocation and deallocation)都取决于该 base class, 而这个 base class 兴许是终端用户无奈触碰和操作的(user-configurable)

很难挑选出某个调配策略说它能提供最大利益而不至于令某些行为适度劣势。事实上,就算要筛选何种典型动作以测量速度,都是一种艰难

GNU C++ 提供三项综合测试(three synthetic benchmarks)用以实现 C++ allocators 之间的速度比照:

Insertion, 通过屡次 insertions 后各种 STL 容器将领有某些及大量。别离测试循序式(sequence)和关联式(assiciative)容器

多线程环境中的 insertion and erasure, 这个测试展现 allocator 偿还内存的能力,以及测量线程之间对内存的竞争

A threaded producer/consumer model, 分别离测试循序式(sequence)和关联式(assiciative)容器

令两个智能型 allocator:

__gnu_cxx::debug_allocator(用途极少)

这是一个外覆器(wrapper), 可包覆于任何 allocator 之上,它把客户的申请量增加一些,而后由 allocator 回应,并以那一小块额定内存搁置 size 信息。一旦 deallocate() 收到一个 pointer,就会查看 size 并以 assert() 保障吻合

__gnu_cxx::array::allocator

容许调配一已知固定大小(known and fixed size)的内存块,内存来自 std::array objects(原生的动态数组)。用上这个 allocator, 大小固定的容器(包含 std::string)就无需再调用 ::operator new 和 operator delete。这就容许咱们应用 STL abstractions 而无需再运行期 “ 添乱 ”、减少开销。甚至再 program startup 状况下也可应用(动态分配还没筹备好的状况下)

退出移动版