当前位置:网站首页>utlis 内存池 对象池

utlis 内存池 对象池

2022-06-30 09:32:00 Zip-List

utils 内存池

内存池负责管理多个对象池,对象池负责管理多个对象

空间非连续,用时分配

对象池

对象池类的变量 map<mid_t, T*>负责记录正在使用的内存映射,POD类型的对象池,size时确定的

UNIT_POOL_BASE
+u64 _type
+int _num_limit
+int _unit_size
+int _max_used
+string _type_name
+alloc_unit() : virtual
+get_unit() : virtual
+free_unit() : virtual
+get_cur_use_num() : virtual
UNIT_POOL
+std::map _map_use
class UNIT_POOL_BASE
{
    
public:
    virtual mid_t alloc_unit() = 0;
    virtual void free_unit(mid_t mid) = 0;
    virtual void* get_unit(mid_t mid) = 0;
    virtual int get_cur_use_num() = 0;

public:
    u16 _type;                       // pool type
    int _num_limit;                  // 数量限制
    int _unit_size;                  // 单个unit大小
    int _max_used;                   // 最大用了多少个
    std::string _type_name;          // type name
};

template<typename T>
class UNIT_POOL : UNIT_POOL_BASE
{
    
public:
    typedef typename std::map<mid_t, T*>::iterator IT;
    UNIT_POOL()
    {
    
        _map_use.clear();
        _num_limit = 0;
        _max_used = 0;
        _type_name = "";
    }

    ~UNIT_POOL()
    {
    
        for (auto& itr : _map_use)
        {
    
            if (itr->second)
            {
    
                delete (itr->second); //delete 指针时会调用指针所指对象的析构函数
            }
        }
        _map_use.clear();
    }

    virtual mid_t alloc_unit();
    virtual void free_unit(mid_t mid);
    virtual void* get_unit(mid_t mid);
    virtual int get_cur_use_num();

private:
    std::map<mid_t, T*> _map_use;  // 正在使用的内存映射
};

小技巧,使用位域在按type分配时,加入序列号信息。对象记录了自己的type可以反查到对应对象池的信息

typedef struct unitmid_t
{
    
    u64      type : 16;
    u64      serial : 48;
} unitmid_t;

inline mid_t alloc_mid(u16 type)
{
    
    static u64 base_id = 10000;
    ++base_id;

    unitmid_t unit_mid;
#pragma GCC diagnostic ignored "-Wconversion"
    unit_mid.type = type;
    unit_mid.serial = base_id;
#pragma GCC diagnostic pop
    return *(mid_t *)&unit_mid;
}

相应函数实现 分配对象 获取对象 释放对象

template<typename T>
mid_t UNIT_POOL<T>::alloc_unit()
{
    
    if (_num_limit <= (int)_map_use.size())
    {
    
        fatal_log("type:%d type_name:%s alloc fail, cur use:%d upper limit exceeded"
                    , _type, _type_name.c_str(), (int)_map_use.size());
        return INVALID_MID;
    }

    void* data = malloc(_unit_size);
    assert_retval(data, INVALID_MID);

    // placement new
    memset((char*)data, 0x00, _unit_size);
    T* ptr = new(data) T;
    assert_retval(ptr != nullptr, INVALID_MID);

    mid_t mid = alloc_mid(_type);
    _map_use[mid] = ptr;

    if (_max_used < (int)_map_use.size())
    {
    
        _max_used = (int)_map_use.size();
    }

    return mid;
}

#pragma GCC diagnostic ignored "-Wdelete-non-virtual-dtor"
template<typename T>
void UNIT_POOL<T>::free_unit(mid_t mid)
{
    
    IT itr = _map_use.find(mid);
    if (itr == _map_use.end())
    {
    
        return;
    }

    T* ptr = itr->second; // 在已分配存储中构造(“布置”)
    _map_use.erase(itr);

    assert_retnone(ptr);
    ptr->~T(); // free并不会调用对象的析构,要手动调用

    // free
    free((void*)ptr);

}
#pragma GCC diagnostic warning "-Wdelete-non-virtual-dtor"

template<typename T>
void* UNIT_POOL<T>::get_unit(mid_t mid)
{
    
    IT itr = _map_use.find(mid);
    if (itr == _map_use.end())
    {
    
        return nullptr;
    }

    return itr->second;
}

template<typename T>
int UNIT_POOL<T>::get_cur_use_num()
{
    
    return (int)_map_use.size();
}

内存池

对象池根据编号管理对应的对象池

 std::map<int, UNIT_POOL_BASE*>  g_map_pool; //全局的内存池 装有对象池的地址

相应函数封装 分配对象 获取对象 释放对象

/** @brief 内存池初始化和回收,进程启动和退出时调用 */
int mempool_init();
void mempool_fini();

/** @brief 对象类型注册 @param[in] type -- 内存对象类型 @param[string] type_name -- 内存type名字 @param[in] num_limit -- 内存数量限制 @param[UNIT_POOL_BASE] pool_fn -- 内存对象管理指针 @retval 0 -- 成功 @retval <0 -- 失败 */
int unitpool_init(u16 type, const char* type_name, int num_limit, int unit_size, UNIT_POOL_BASE* unit_pool);

/** @brief 申请对象 // 申请对象,调用内存池中固定类型对象池的分配对象 @param[in] type -- 内存对象类型 @retval =INVALID_MID -- 失败 @retval 其他值-- 成功,对象的mid标志 */
mid_t memunit_alloc(u16 type);

/** @brief 对象释放 @param[in] type -- 内存对象类型 */
void memunit_free(mid_t mid);

/** @brief 获得对象内存地址 @param[in] type -- 内存对象类型 @retval =nullptr -- 失败,找不到该对象 @retval !=nullptr-- 成功,对象的内存地址 */
void* memunit_get(mid_t mid);

具体实现

int mempool_init()
{
    
    g_map_pool.clear();
    return 0;
}

void mempool_fini()
{
    
    g_map_pool.clear();
}

int unitpool_init(u16 type, const char* type_name, int num_limit, int unit_size, UNIT_POOL_BASE* unit_pool)
{
    
    assert_retval(unit_pool && type_name, BGERR_INVALID_ARG);
    assert_retval(type >= 0 && type < MAX_POOL_TYPE_NUM, BGERR_INVALID_ARG);
    assert_retval(num_limit > 0, BGERR_INVALID_ARG);

    auto itr = g_map_pool.find(type);
    if (itr != g_map_pool.end())
    {
    
        assert_retval(0, BGERR_INVALID_ARG);
    }

    unit_pool->_type = type;
    unit_pool->_num_limit = num_limit;
    unit_pool->_type_name = type_name;
    unit_pool->_unit_size = unit_size;

    g_map_pool[type] = unit_pool;

    infor_log("unitpool init, type:%d name:%s num_limit:%d", type, type_name, num_limit);

    return 0;
}

mid_t memunit_alloc(u16 type) 
{
    
    auto itr = g_map_pool.find(type);
    if (itr == g_map_pool.end() || !itr->second)
    {
    
        assert_retval(0, INVALID_MID);
    }

    return itr->second->alloc_unit();
}

void memunit_free(mid_t mid)
{
    
    unitmid_t *unitmid = (unitmid_t *)&mid;
    int type = unitmid->type;

    auto itr = g_map_pool.find(type);
    if (itr == g_map_pool.end() || !itr->second)
    {
    
        //assert_retnone(0);
        return;
    }

    itr->second->free_unit(mid);
}


void* memunit_get(mid_t mid)
{
    
    unitmid_t *unitmid = (unitmid_t *)&mid;
    int type = unitmid->type;

    auto itr = g_map_pool.find(type);
    if (itr == g_map_pool.end() || !itr->second)
    {
    
        //assert_retval(0, nullptr);
        return nullptr;
    }

    return itr->second->get_unit(mid);
}
#define POOL_REGISTER(MEM_TYPE_ID, MEM_TYPE_NAME, MEM_STRUCT_TYPE, MEM_UNIT_NUM) \ do {
      \ UNIT_POOL<MEM_STRUCT_TYPE>* unit_pool = new UNIT_POOL<MEM_STRUCT_TYPE>;\ if (nullptr == unit_pool)\ {
      \ error_log("mem type: %s create register deal fn failed", #MEM_TYPE_ID); \ return BGERR_UNKNOWN; \ }\ int ret = bg_unitpool_init(MEM_TYPE_ID, MEM_TYPE_NAME, MEM_UNIT_NUM, sizeof(MEM_STRUCT_TYPE), (UNIT_POOL_BASE*)unit_pool);\ if (0 != ret)\ {
      \ error_log("mem type: %s register deal fn failed, retval: %d", \ #MEM_TYPE_ID, BGERR_UNKNOWN); \ return ret; \ }\ }while(0)

思考

  • 对象池用时分配,并未在连续空间上分配,如果连续空间要初始化时分配所有空间,对对象的管理可以使用map或者free_list记录,或者数组记录第几块被使用

  • 连续空间如何防止边缘部分被写坏,非连续空间段错误,连续空间加入保护部分,转型使用dynamic_cast

原网站

版权声明
本文为[Zip-List]所创,转载请带上原文链接,感谢
https://blog.csdn.net/qq_41565920/article/details/125121523