SGI STL内存池源码(无各种宏定义,纯C++风格)

#include <iostream>
#include <cstddef>

// 内存块结构体
union obj {
    union obj* free_list_link;  // 指向下一个空闲内存块的指针
    char client_data[1];        // 实际存储数据的位置
};

// 二级空间配置器类
class DefaultAllocTemplate {
private:
    // 自由链表数组,每个元素指向一个空闲内存块链表
    static obj* volatile free_list[16];
    // 计算需要的内存块大小对应的自由链表索引
    static size_t FREELIST_INDEX(size_t bytes) {
        return ((bytes + 8 - 1) / 8 - 1);
    }
    // 调整请求的内存大小,使其为 8 的倍数
    static size_t ROUND_UP(size_t bytes) {
        return (((bytes)+8 - 1) & ~(8 - 1));
    }
    // 从内存池中取出内存块填充自由链表
    static void* refill(size_t n);
    // 从操作系统申请一大块内存作为内存池
    static char* chunk_alloc(size_t size, int& nobjs);
    // 内存池起始指针
    static char* start_free;
    // 内存池结束指针
    static char* end_free;
    // 内存池当前可用大小
    static size_t heap_size;

public:
    // 分配内存
    static void* allocate(size_t n) {
        obj* volatile* my_free_list;
        obj* result;
        // 如果请求的内存大小超过 128 字节,使用一级空间配置器
        if (n > 128) {
            return std::malloc(n);
        }
        // 找到对应的自由链表
        my_free_list = free_list + FREELIST_INDEX(n);
        result = *my_free_list;
        // 如果自由链表为空,需要重新填充
        if (result == nullptr) {
            void* r = refill(ROUND_UP(n));
            return r;
        }
        // 从自由链表中取出一个内存块
        *my_free_list = result->free_list_link;
        return result;
    }
    // 释放内存
    static void deallocate(void* p, size_t n) {
        obj* q = static_cast<obj*>(p);
        obj* volatile* my_free_list;
        // 如果释放的内存大小超过 128 字节,使用一级空间配置器的释放方法
        if (n > 128) {
            std::free(p);
            return;
        }
        // 找到对应的自由链表
        my_free_list = free_list + FREELIST_INDEX(n);
        // 将释放的内存块插入自由链表头部
        q->free_list_link = *my_free_list;
        *my_free_list = q;
    }
};

// 初始化静态成员变量
obj* volatile DefaultAllocTemplate::free_list[16] = { nullptr };
char* DefaultAllocTemplate::start_free = nullptr;
char* DefaultAllocTemplate::end_free = nullptr;
size_t DefaultAllocTemplate::heap_size = 0;

// 从内存池中取出内存块填充自由链表
void* DefaultAllocTemplate::refill(size_t n) {
    int nobjs = 20;
    // 从内存池分配内存块
    char* chunk = chunk_alloc(n, nobjs);
    obj* volatile* my_free_list;
    obj* result;
    obj* current_obj;
    obj* next_obj;
    // 如果只分配到一个内存块,直接返回给调用者
    if (nobjs == 1) {
        return chunk;
    }
    // 找到对应的自由链表
    my_free_list = free_list + FREELIST_INDEX(n);
    // 将第一个内存块返回给调用者
    result = (obj*)chunk;
    // 将剩余的内存块连接成自由链表
    *my_free_list = next_obj = (obj*)(chunk + n);
    for (int i = 1; ; i++) {
        current_obj = next_obj;
        next_obj = (obj*)((char*)next_obj + n);
        if (i == nobjs - 1) {
            current_obj->free_list_link = nullptr;
            break;
        }
        else {
            current_obj->free_list_link = next_obj;
        }
    }
    return result;
}

// 从操作系统申请一大块内存作为内存池
char* DefaultAllocTemplate::chunk_alloc(size_t size, int& nobjs) {
    char* result;
    size_t total_bytes = size * nobjs;
    size_t bytes_left = end_free - start_free;
    // 如果内存池剩余空间足够
    if (bytes_left >= total_bytes) {
        result = start_free;
        start_free += total_bytes;
        return result;
    }
    // 如果内存池剩余空间能分配部分内存块
    else if (bytes_left >= size) {
        nobjs = bytes_left / size;
        total_bytes = size * nobjs;
        result = start_free;
        start_free += total_bytes;
        return result;             
    }
    // 如果内存池剩余空间不足
    else {
        size_t bytes_to_get = 2 * total_bytes + ROUND_UP(heap_size >> 4);
        // 如果内存池还有剩余空间,将其插入对应的自由链表
        if (bytes_left > 0) {
            obj* volatile* my_free_list = free_list + FREELIST_INDEX(bytes_left);
            ((obj*)start_free)->free_list_link = *my_free_list;
            *my_free_list = (obj*)start_free;
        }  
        // 向操作系统申请新的内存
        start_free = (char*)std::malloc(bytes_to_get);
        if (start_free == nullptr) {
            // 如果申请失败,尝试从其他自由链表中获取内存
            obj* volatile* my_free_list;
            obj* p;
            for (size_t i = size; i <= 128; i += 8) {
                my_free_list = free_list + FREELIST_INDEX(i);
                p = *my_free_list;
                if (p != nullptr) {
                    *my_free_list = p->free_list_link;
                    start_free = (char*)p;
                    end_free = start_free + i;
                    return chunk_alloc(size, nobjs);
                }
            }
            // 如果还是失败,调用一级空间配置器的异常处理机制
            std::abort();
        }
        heap_size += bytes_to_get;
        end_free = start_free + bytes_to_get;
        return chunk_alloc(size, nobjs);
    }
}


// 测试代码
int main() {
    // 分配一个 20 字节的内存块
    void* p = DefaultAllocTemplate::allocate(20);
    // 释放该内存块
  
    DefaultAllocTemplate::deallocate(p, 20);
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值