【STL】 SGI空间配置器(二):第一级配置器

对SGI空间配置器的背景介绍可参考此篇博文,空间配置器背景介绍
这篇主要总结下SGI空间配置器的第一级配置器。

一、源码剖析
#if 0
#   include <new>
#   define __THROW_BAD_ALLOC throw bad_alloc
#elif !defined(__THROW_BAD_ALLOC)
#   include <iostream.h>
#   define __THROW_BAD_ALLOC cerr << "out of memory" << endl; exit(1)
#endif

template <int inst>
class __malloc_alloc_template {

private:
//以下函数将用来处理内存不足的情况
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()
    free(p);
}

static void * reallocate(void *p, size_t /* old_sz */, size_t new_sz)
{
    //第一级配置器直接使用realloc()
    void * result = realloc(p, new_sz);
    //当申请不到内存时,改用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
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;

    //不断尝试释放、配置、再释放、再配置...
    //释放函数通过set_malloc_handler指定。
    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;

    //不断尝试释放、配置、再释放、再配置...
    //释放函数通过set_malloc_handler指定。
    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);
    }
}

typedef __malloc_alloc_template<0> malloc_alloc;

//SGI对alloc接口的再次包装,使配置器接口能够符合STL规格。
//simple_alloc内部的四个成员函数都是单纯的转调用,调用传递给
//配置器(可能是第一级,也可能是第二级)的成员函数。SGI STL容器
//全部使用这个simple_alloc接口。
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)); }
};

二、总结

1、第一级配置器以malloc()free()realloc()等C函数执行实际的内存配置、释放、重配置等操作,并实现出类似C++ new handler的机制。配置器不是直接使用::operator new来配置内存的,所以不能直接运用C++ new handler机制。

2、所谓C++ new handler机制,指你可以要求系统在内存配置需求无法被满足时,调用一个你指定的函数。换句话说,一旦::operator new无法完成任务,在丢出std::bad_alloc异常状态前,会先调用由客端指定的处理例程。该处理例程通常即被称为new-handler。另new-handler解决内存不足的做法是有特定的模式的。
这里举个例子:

void outOfMem()
{
	std::cerr << "Unable to satisfy request for memory\n";
	std::abort()
}

int main()
{
	std::set_new_handler(outOfMem);
	int* pBigDataArray = new int[100000000L];
	...
}

本例中,如果operator new 无法为100,000,000个整数分配足够的空间,outOfMem则会被调用。

3、SGI以malloc而非::operator new来配置内存,作者认为两个原因,一是历史因素,二是C++并未提供相应于realloc()的内存配置操作,因此SGI不能直接使用C++的set_new_handler(),必须仿真一个类似的set_malloc_handler(),查看SGI STL源码,好像都没设置这个参数,也就是说内存不足时,直接跑异常。

4、SGI第一级配置器allocate()和realloc()都是在调用malloc()和realloc()失败后,改调用oom_malloc()和oom_realloc()。后两者都有内部循环,不断调用"内存不足处理例程",期望在某次调用之后,获得足够的内存而圆满完成任务,若"内存不足处理例程"并未被客端设定,oom_malloc()和oom_realloc()则会抛出bad_alloc异常信息,或利用exit(1)硬生生中止程序。
设计“内存不足处理例程”是客端的责任,设定“内存不足处理例程”也是客端的责任。另外“内存不足处理例程”解决问题的做法有着特定的模式,使用者要多注意。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值