OceanBase系统有一个全局的定长内存池,这个内存池中维护了由64KB大小的定长的内存块组成的空闲链表。
-
如果申请的内存不超过64KB,则尝试从空闲链表中获取一个64KB的内存块返回给申请者;如果空闲链表为空,需要首先从操作系统中申请若干个大小为64KB的内存块加入到空闲链表中。释放时将64KB的内存块返回给空闲链表中以供下次使用。(有点类似于线程池的意思)
-
如果申请的内存超过64KB,直接调用Glibc的内存分配函数,向操作系统申请用户所需大小的内存块,释放时直接调用Glibc的内存释放函数,将内存归还给操作系统。注意如果申请的是大内存的话,就需要直接和操作系统进行交互了。
namespace oceanbase
{
namespace common
{
class ObIAllocator
{
public:
virtual ~ObIAllocator() {};
public:
virtual void *alloc(const int64_t sz) = 0;
virtual void free(void *ptr) = 0;
//申请模块 #define UNUSED(v) ((void)(v))
virtual void* mod_alloc(const int64_t size, const int32_t mod_id = 0){ UNUSED(size); UNUSED(mod_id); return NULL; }
//释放模块
virtual void mod_free(void* p, const int32_t mod_id = 0) { UNUSED(p); UNUSED(mod_id); }
virtual void set_mod_id(int32_t mod_id) = 0;
};
}
}
//ObMalloc和ObTCMalloc是上面ObIAllocator的两个实现
//区别在于ObMalloc不支持线程缓存,而ObTCMalloc支持线程缓存
class ObMalloc : public ObIAllocator
{
public:
ObMalloc() : mod_id_(0) {};
explicit ObMalloc(int32_t mod_id) : mod_id_(mod_id) {};
~ObMalloc() {};
public:
void set_mod_id(int32_t mod_id) {mod_id_ = mod_id;};
void *alloc(const int64_t sz) {return ob_malloc(sz, mod_id_);};
void free(void *ptr) {ob_free(ptr);};
void* mod_alloc(const int64_t size, const int32_t mod_id){ return ob_malloc(size, mod_id); }
void mod_free(void* p, const int32_t mod_id) { return ob_free(p, mod_id); }
private:
int32_t mod_id_;
};
class ObTCMalloc : public ObIAllocator
{
public:
ObTCMalloc() : mod_id_(0) {};
~ObTCMalloc() {};
public:
void set_mod_id(int32_t mod_id) {mod_id_ = mod_id;};
void *alloc(const int64_t sz) {return ob_tc_malloc(sz, mod_id_);};
void free(void *ptr) {ob_tc_free(ptr, mod_id_);};
private:
int32_t mod_id_;
};
//上面的ob_tc_mclloc(sz,mod_id_)调用的是这个方法
ObTSIBlockAllocator::Block* ObTSIBlockAllocator::mod_alloc_block(int64_t size, const int32_t mod_id)
{
int err = OB_SUCCESS;
Block* block = NULL;
int64_t alloc_size = 0;
if (!inited_)
{
err = OB_NOT_INIT;
TBSYS_LOG(ERROR, "not inited.");
}
else if (size <= 0)
{
err = OB_INVALID_ARGUMENT;
TBSYS_LOG(ERROR, "size[%ld] <= 0", size);
}
//OceanBase将block设置为三个级别,分别是normal、medium、big,取最合适的
//如果要申请的size大于big_block_size_,就申请size大小的内存
//还需要为每个申请的内存设置模块号
else if (normal_block_size_ >= size)
{
alloc_size = normal_block_size_;
block = normal_block_cache_.get();
}
else if (medium_block_size_ >= size)
{
alloc_size = medium_block_size_;
block = medium_block_cache_.get();
}
else if (big_block_size_ >= size)
{
alloc_size = big_block_size_;
block = big_block_cache_.get();
/*
//首先尝试从线程局部的空闲链表申请内存块,如果申请不到,再通过ObMalloc的alloc方法申请
TSIBlockCache::Block* TSIBlockCache::get()
{
BlockList* block_list = NULL;
Block* block = NULL;
if (!inited_)
{
TBSYS_LOG(ERROR, "not inited");
}
else if (NULL == (block_list = get_block_list_head()))
{
TBSYS_LOG(ERROR, "get_block_list()=>NULL");
}
else if (NULL != (block = block_list->pop()))
{
// do nothing
}
else if (OB_SUCCESS == global_block_list_.pop(block))
{
// do nothing
}
return block;
}
*/
}
else
{
alloc_size = size;
//TBSYS_LOG(TRACE, "alloc big block size[%ld]", size);
}
if (OB_SUCCESS == err && NULL == block)
{
block = alloc_block(alloc_size);
//new(p) Block(size); 此处使用了placement_new
}
if (NULL != block)
{
block->real_size_ = size;
block->mod_ = mod_id;
after_alloc(block);
//更新全局内存池的大小
g_malloc_size_stat.add(size);
ob_mod_usage_update(alloc_size, mod_id);
ob_mod_usage_update(alloc_size, ObModIds::OB_MOD_TC_ALLOCATED);
//BACKTRACE(WARN, block->size_ > 65536, "block_size=%ld", block->size_);
}
return block;
}