STL中的空间配置器

一般我们习惯的c++内存配置如下

class Foo { ... };
Foo* pf = new Foo;
delete pf;

这里的new实际上分为两部分执行。首先是先用::operator new配置内存,然后执行Foo::Foo()构造对象内容。delete也一样,先运行Foo::~Foo()析构对象,再用::operator delete释放内存。在SGI STL中,这两部分分别在<stl_alloc.h>和<stl_construct.h>中。本文讲的便是<stl_alloc.h>中的故事。
  SGI STL中将配置器分为两级。第一级直接用malloc和free管理内存,第二级则使用内存池以避免内存碎片。这两级都由simple_alloc包装起来以符合stl标准。如图

STL中的空间配置器

第一级由于没有用operator new,所以要自己实现new-handler机制。我仿写的代码如下

#ifndef _MALLOC_ALLOC_H_
#define _MALLOC_ALLOC_H_

//定义内存不足又没有定义相关处理函数时抛出的异常
#ifndef THROW_OOM
#    include <stdio.h>
#    include <stdlib.h>
#    define THROW_OOM fprintf(stderr, "out of memory\n"); exit(1)
#endif

#include<stdlib.h>

namespace Chenstl{

//第一级空间配置器,直接用mallloc分配内存
//当需要分配的空间大于MAX_BYTES时使用
    class malloc_alloc{
    private:
        static void *oom_malloc(size_t);    //声明时可以只写类型啊。。现在才知道
        static void *oom_realloc(void *,size_t);
        static void (* malloc_oom_handler)();    //处理malloc时内存不足时的函数指针
    public:
        static void *allocate(size_t n);
        static void decllocate(void *p);

static void *realloc(void *p, size_t new_sz);
        //当内存不足时,需要客户端设置handler
        static void set_malloc_oom_handler(void(*f)());
    };   
}

#endif

----------------------------------------------------------------------------------

#include "malloc_alloc.h"

using namespace Chenstl;
void *malloc_alloc::allocate(size_t n)
{
    void *result = malloc(n);
    if (0 == result) result = oom_malloc(n);
    return result;
}

void malloc_alloc::decllocate(void *p)
{
    free(p);
}

void * malloc_alloc::realloc(void *p, size_t new_sz)
{
    void *result = realloc(p, new_sz);
    if (0 == result)    result = oom_realloc(p, new_sz);
    return result;
}

//当内存不足时,需要客户端设置handler
void malloc_alloc::set_malloc_oom_handler(void(*f)())
{
    malloc_oom_handler = f;
}

void(*malloc_alloc::malloc_oom_handler)() = 0;

void *malloc_alloc::oom_malloc(size_t n)
{//不断试图获得内存
    void *result;
    for (;;)    //据说这样比while(1)效果更优
    {
        if (0 == malloc_oom_handler) THROW_OOM;
        (*malloc_oom_handler)();
        result = malloc(n);
        if (result)    return result;
    }
}

void *malloc_alloc::oom_realloc(void *p, size_t n)
{
    void *result;
    for (;;)
    {
        if (0 == malloc_oom_handler) THROW_OOM;
        (*malloc_oom_handler)();
        result = realloc(p, n);
        if (result)    return result;
    }
}

malloc_alloc.cpp

如果需要的区块超过128bytes则用第一级,否则用第二级的内存池管理。为了便于管理,配置器会自动将内存需求量上调到8的倍数(要求20bytes时,自动调整为24bytes)。用16个freelist管理内存池,为节省空间,使用union

union obj {  //free-lists的节点构造
  union obj *next;
  char client[1];  //使用者可见
  };

获取内存时的代码及步骤如下

void *default_alloc::allocate(size_t n)
{
    obj *result = 0;
    obj **my_free_list = 0;
    if (n > MAX_BYTES)
        return malloc_alloc::allocate(n);
    //寻找free lists中合适的一个               
    my_free_list = free_list + FREELIST_INDEX(n);
    result = *my_free_list;
    if(0 == result)
    {//没有找到可用的freelist,从内存池里取出空间
        return refill(ROUND_UP(n));
    }
    //调整freelist
    *my_free_list = result->next;
    return result;
}

STL中的空间配置器

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/102b355f40f3daf6aefb7bdbde8845d7.html