《STL源码剖析》—— 空间配置器(三)

一、空间的配置与释放,std::alloc

        对象构造前的空间配置和对象析构后的空间释放,由<stl_alloc.h>负责,SGI对此的设计哲学如下:

        1. 向 system heap 要求空间。

        2. 考虑多线程(multi-threads)状态。

        3. 考虑内存不足时的应变措施。

        4. 考虑过多“小型区块”可能造成的内存碎片(fragment)问题。


        考虑到小型区块所可能造成的内存破碎问题,SGI设计了双层级配置器,第一级配置器直接使用 malloc() 和 free() ,第二级配置器则视情况采用不同的策略:当配置区块超过 128 bytes时,视之为“足够大”,便调用第一级配置器;当配置区块小于 128 bytes时,视之为“过小”,为了降低额外负担,便采用复杂的 memory pool 整理方式,而不再求助于第一级配置器。

        在SGI的整个设计究竟只开放第一级配置器,或是同时开放第二级配置器,取决于 __USE_MALLOC 是否被定义。

#ifdef  __USE_MALLOC
...
typedef __malloc_alloc_template<0>  malloc_alloc;
typedef malloc_alloc  alloc;  // 令 alloc 为第一级配置器
#else
...
// 令 alloc 为第二级配置器
typedef __default_alloc_template<__NODE_ALLOCATOR_THREADS, 0>  alloc;
#endif /* ! __USE_MALLOC */
         其中 __malloc_alloc_template 就是第一级配置器,__default_alloc_template 就是第二级配置器。SGI STL并未定义 __USE_MALLOC,所以SGI使用第二级配置器。


         SGI 还为 alloc 包装了一个接口如下,使配置器的接口能够符合 STL 规格:

template<class T, class Alloc>
class simple_alloc {

public:
    static T *allocate(size_t n)
                { return 0 == n? 0 : (T*) Alloc::allocate(n * sizeof (T)); }
    static T *allocate(void)
                { return (T*) Alloc::allocate(sizeof (T)); }
    static void deallocate(T *p, size_t n)
                { if (0 != n) Alloc::deallocate(p, n * sizeof (T)); }
    static void deallocate(T *p)
                { Alloc::deallocate(p, sizeof (T)); }
};
          其内部四个成员函数其实都是单纯的转调用,调用传递给配置器的成员函数。SGI STL容器全部使用这个 simple_alloc 接口。


二、第一级配置器 __malloc_alloc_template 剖析

// 注意,无"template型别参数"。至于"非型别参数"inst,则完全没派上用场
template <int inst>
class __malloc_alloc_template {

private:
// 以下函数将用来处理内存不足的情况
// oom : out of memory
static void *oom_malloc(size_t);

static void *oom_realloc(void *, size_t);

#ifndef __STL_STATIC_TEMPLATE_MEMBER_BUG
    static void (* __malloc_alloc_oom_handler)();
#endif

public:

static void * allocate(size_t n)
{
    void *result = malloc(n); // 第一级配置器直接使用 malloc()
    // 以下无法满足需求时,改用 oom_malloc()
    if (0 == result) result = oom_malloc(n);
    return result;
}

static void deallocate(void *p, size_t /* n */)
{
    free(p); // 第一级配置器直接使用 free()
}

static void * reallocate(void *p, size_t /* old_sz */, size_t new_sz)
{
    void * result = realloc(p, new_sz); // 第一级配置器直接使用 realloc()
    // 以下无法满足需求时,改用 oom_realloc()
    if (0 == result) result = oom_realloc(p, new_sz);
    return result;
}

// 以下仿真C++的 set_new_handler()。换句话说,可以通过它
// 指定你自己的 out-of-memory handler
static void (* set_malloc_handler(void (*f)()))()
{
    void (* old)() = __malloc_alloc_oom_handler;
    __malloc_alloc_oom_handler = f;
    return(old);
}

};

// malloc_alloc out-of-memory handling

#ifndef __STL_STATIC_TEMPLATE_MEMBER_BUG
// 初值为 0。有待客端设定
template <int inst>
void (* __malloc_alloc_template<inst>::__malloc_alloc_oom_handler)() = 0;
#endif

template <int inst>
void * __malloc_alloc_template<inst>::oom_malloc(size_t n)
{
    void (* my_malloc_handler)();
    void *result;

    for (;;) { // 不断尝试释放、配置、再释放、再配置...
        my_malloc_handler = __malloc_alloc_oom_handler;
        if (0 == my_malloc_handler) { __THROW_BAD_ALLOC; }
        (*my_malloc_handler)(); // 调用处理例程,企图释放内存
        result = malloc(n);     // 再次尝试配置内存
        if (result) return(result);
    }
}

template <int inst>
void * __malloc_alloc_template<inst>::oom_realloc(void *p, size_t n)
{
    void (* my_malloc_handler)();
    void *result;

    for (;;) { // 不断尝试释放、配置、再释放、再配置...
        my_malloc_handler = __malloc_alloc_oom_handler;
        if (0 == my_malloc_handler) { __THROW_BAD_ALLOC; }
        (*my_malloc_handler)(); // 调用处理例程,企图释放内存
        result = realloc(p, n); // 再次尝试配置内存
        if (result) return(result);
    }
}

// 注意,以下直接将参数 inst 指定为 0
typedef __malloc_alloc_template<0> malloc_alloc;
        第一级配置器以 malloc(),free(),realloc()等 C 函数执行实际的内存配置、释放、重配置操作,并实现出类似 C++ new-handler 的机制。(所谓 C++ new handler 机制是,你可以要求系统在内存配置需求无法被满足时,调用一个你所指定的函数。换句话说,一旦 ::operator new 无法完成任务,在丢出 std::bad_alloc 异常状态之前,会先调用由客端指定的处理例程。)

        设计“内存不足处理例程”是客端的责任,设定“内存不足处理例程”也是客端的责任。


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值