STL源码剖析:空间配置器

看完自己重写了一下,不知道的又看了一遍,里面没有考虑多线程的问题,主要是想实现以下内存池。

Mempool.h

#ifndef MEMPOOL_H_
#define MEMPOOL_H_

#include <cstddef>
#include <new>
#include <cstdlib>

namespace flysnow {

enum {STEP_ = 8};
enum {MAX_BYTES_ = 128};
enum {FREELIST_NUM_ = MAX_BYTES_/STEP_};

class Mempool{

private:
    union pool_bucket {
        union pool_bucket* next_node;
        char bucket_addr[1];
    };
    static size_t up_to_nearest(size_t n) {
        return STEP_*((n>>3) + (n%8 ? 1:0));
    }

    static size_t freelist_index(size_t n) {
        return ((n>>3) + (n%8 ? 0:-1));
    }

    static void* refill(size_t n);
    static char* alloc_memory(size_t size,int &pool_node_num);

    static pool_bucket* free_list_[FREELIST_NUM_];
    static char* start_pool;
    static char* end_pool;
    static size_t heap_size;

public:
    static void* allocate(size_t n);
    static void deallocate(void *p,size_t n);
    static size_t get_heap_size() {return heap_size;}
};

}
#endif

Mempool.cpp

#include "mempool.h"

namespace flysnow{

char* Mempool::start_pool = 0;
char* Mempool::end_pool = 0;
size_t Mempool::heap_size = 0;
Mempool::pool_bucket* Mempool::free_list_[FREELIST_NUM_] =
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
void* Mempool::allocate(size_t n) {
    if(n > MAX_BYTES_){
        return malloc(n);
    }
    pool_bucket *p;
    pool_bucket **free_list_index = free_list_ + freelist_index(n);
    p = *free_list_index;
    if(0 == p) {
        void *q = refill(up_to_nearest(n));
        return q;
    }
    *free_list_index = p->next_node;
    return p;
}

void Mempool::deallocate(void *p,size_t n) {
    pool_bucket *q = (pool_bucket*)p;
    if(n > MAX_BYTES_) {
        free(p);
        return ;
    }
    pool_bucket **free_list_index = free_list_ + freelist_index(n);

    q->next_node = *free_list_index;
    *free_list_index = q;
}

void* Mempool::refill(size_t n) {
    int pool_node_num = 20;
    int i;
    pool_bucket **free_list_index = free_list_ + freelist_index(n);
    char *pool = alloc_memory(n,pool_node_num);
    if(1 == pool_node_num) {
        return pool;
    }

    pool_bucket *result = (pool_bucket*)pool;
    pool_bucket *current,*next;
    pool += n;
    *free_list_index = next = (pool_bucket*)pool;
    next = (pool_bucket*)pool;
    for(i=1; ;++i){
        current = next;
        next = (pool_bucket*)((char*)next + n);
        if(pool_node_num - 1 == i){
            current->next_node = NULL;
            break;
        } else {
            current->next_node = next;
        }
    }
    return result;
}

char* Mempool::alloc_memory(size_t size,int &pool_node_num) {
    size_t total_size = size*pool_node_num;
    size_t remain_size = end_pool - start_pool;
    if(total_size <= remain_size) {
        char* result = start_pool;
        start_pool += total_size;
        return result;
    } else if(remain_size >= size) {
        pool_node_num = remain_size/size;
        size_t return_size = pool_node_num*size;
        char *result = start_pool;
        start_pool += return_size;
        return result;
    } else {
        size_t get_size = 2*total_size + up_to_nearest(heap_size>>4);
        if(remain_size > 0) {
            //如果剩余7byte,此处会放在8byte的自由链表中,然而,最后allocate 8byte的
            //时候,岂不会出错?
            //原来之前get_size分配的内存总是8的倍数,因此不会出现以上情况。。。。
            pool_bucket **free_list_index = free_list_ + freelist_index(remain_size);
            ((pool_bucket*)start_pool)->next_node = *free_list_index;
            *free_list_index = (pool_bucket*)start_pool;
        }

        start_pool = (char*)malloc(get_size);
        if(0 == start_pool) {
            pool_bucket **free_list_index;
            pool_bucket *p;
            for(int i=size;i<=MAX_BYTES_;i+=STEP_) {
                free_list_index = free_list_ + freelist_index(i);
                p = *free_list_index;
                if(0 != p) {
                    *free_list_index = p->next_node;
                    start_pool = (char*)p;
                    end_pool = start_pool + i;
                    return (alloc_memory(size,pool_node_num));
                }
            }
            end_pool = 0;
            start_pool = (char*)malloc(get_size);
        }

        heap_size += get_size;
        end_pool = start_pool + get_size;
        //return (alloc_memory(size,pool_node_num));
        char *result = start_pool;
        start_pool += total_size;
        return result;
    }

}

}

main.cpp

#include <iostream>
#include "mempool.h"

using namespace std;

int main()
{
    char *p;
    for(size_t i=0;i<100000;++i){
       p = (char*)flysnow::Mempool::allocate(i%1029+1);
       cout<<flysnow::Mempool::get_heap_size()<<' ';
    }
    cout << endl;
    system("PAUSE");
    return 0;
}
时间: 2024-12-14 09:05:15

STL源码剖析:空间配置器的相关文章

STL源码剖析 — 空间配置器(allocator)

前言 以STL的实现角度而言,第一个需要介绍的就是空间配置器,因为整个STL的操作对象都存放在容器之中. 你完全可以实现一个直接向硬件存取空间的allocator. 下面介绍的是SGI STL提供的配置器,配置的对象,是内存.(以下内容来自<STL源码剖析>) 空间配置器的标准接口 根据STL的规范,allocator的必要接口 各种typedef 1 allocator::value_type 2 allocator::pointer 3 allocator::const_pointer 4

STL源码剖析 --- 空间配置器 std::alloc

STL是建立在泛化之上的.数组泛化为容器,参数化了所包含的对象的类型.函数泛化为算法,参数化了所用的迭代器的类型.指针泛化为迭代器,参数化了所指向的对象的类型.STL中的六大组件:容器.算法.迭代器.配置器.适配器.仿函数. 这六大组件中在容器中分为序列式容器和关联容器两类,正好作为STL源码剖析这本书的内容.迭代器是容器和算法之间的胶合剂,从实现的角度来看,迭代器是一种将operator*.operator->.operator++.operator-等指针相关操作予以重载的class tem

STL源码剖析——空间配置器Allocator#2 一/二级空间配置器

上节学习了内存配置后的对象构造行为和内存释放前的对象析构行为,在这一节来学习内存的配置与释放. C++的内存配置基本操作是::operator new(),而释放基本操作是::operator delete().这两个全局函数相当于C的malloc() 和free() 函数.而SGI正是以malloc() 和free() 完成内存的配置与释放. 考虑到小型区块可能造成的内存破碎问题,SGI设计了两级的空间配置器.第一级直接使用malloc() 和free() ,而第二级则视情况采用不同的策略:当

STL源码剖析--空间配置器

STL的设计非常巧妙,组件间互取短长,形成了一个世界,这是这个世界里的组件: 1. containers(容器):所谓容器,是指存放数据的地方,将数据以一定的方法组织存放.根据不同的组织方式,可以把容器分为顺序容器,如vector.deque.list,关联容器,如set.map.Container是一种class template. 2. algorithm(算法):各种常用不常用的算法如sort.copy.search等等.algorithm是一种function template. 3.

STL源码剖析——空间配置器Allocator#3 自由链表与内存池

上节在学习第二级配置器时了解了第二级配置器通过内存池与自由链表来处理小区块内存的申请.但只是对其概念进行点到为止的认识,并未深入探究.这节就来学习一下自由链表的填充和内存池的内存分配机制. refill()函数——重新填充自由链表 前情提要,从上节第二级配置器的源码中可以看到,在空间配置函数allocate()中,当所需的某号自由链表为空时,才会调用refill()函数来填充链表.refill()函数默认申请20块区块的内存(5行),但所得内存不一定就是20块,要看当前内存池的剩余情况和堆容量的

STL源码分析--空间配置器的底层实现 (二)

STL源码分析-空间配置器 空间配置器中门道 在STL中的容器里都是使用统一的空间配置器,空间配置器就是管理分配内存和销毁内存的.在STL将在heap空间创建一个对象分为两个步骤,第一是申请一块内存,第二是在这块内存中初始化一个对象.首先申请空间是由malloc提供,初始化一个对象时由constructor管理.销毁一个对象也是由两步骤完成,第一是销毁空间上的对象,第二是释放这块内存. 同时,STL的空间配置器分为两级内存,如果申请的内存空间大于128KB,那么就使用第一级空间配置,如果小于,那

STL源码分析--空间配置器 第一级配置器

一.SGI STL配置器简介 SGI STL的配置器与众不同,它与标准规范不同.如果要在程序中明确使用SGI配置器,那么应该这样写: [cpp] view plaincopyprint? vector<int,std::alloc> iv; 他的名字是alloc,而且不接受任何参数.标准配置器的名字是allocator,而且可以接受参数. SGI STL的每一个容器都已经指定了缺省配置器:alloc.我们很少需要自己去指定空间配置器.比如vector容器的声明: [cpp] view plai

STL源码剖析——空间的配置与释放

C++的内存配置基本操作是  ::operator new(),内存释放的基本操作是 ::operator delete().这两个全局函数相当于C的malloc()和free()函数.是的,正是如此,STL正是以malloc()和free()完成内存的配置与释放. 但是考虑到小型区块所可能造成的内存破碎问题,STL中设计了双层级配置器, 第一级配置器直接使用malloc()和free(),第二级配置器则视情况采用不用的策略:当配置区块超过128bytes时,视之为"足够大",便调用第

STL源码剖析---根据最新版本的g++4.9.0(支持C++11)的修订(1)空间配置器

源码剖析采用的G++版本为2.91.57版本,是比较老的版本与最新版本4.9.0有某些方面的差别.现在我针对最新版本做一个分析.我下载了最新的gcc-4.9.0的包作为观察对象: 我们#include <>时的头文件放在:gcc-4.9.0/libstdc++-v3/include/std:例如vector. 真正的实现文件放在:gcc-4.9.0/libstdc++-v3/include/bits:例如:stl_vector,注意前面的stl_. 最后要说的是:技术是不断进步,不断发展变化的

STL&quot;源码&quot;剖析-重点知识总结

STL是C++重要的组件之一,大学时看过<STL源码剖析>这本书,这几天复习了一下,总结出以下LZ认为比较重要的知识点,内容有点略多 :) 1.STL概述 STL提供六大组件,彼此可以组合套用: 容器(Containers):各种数据结构,如:vector.list.deque.set.map.用来存放数据.从实现的角度来看,STL容器是一种class template. 算法(algorithms):各种常用算法,如:sort.search.copy.erase.从实现的角度来看,STL算法