内存池模型设计探讨二
2006-07-10 22:29
267 查看
链表方式的内存管理特点是可以管理足够多的对象(对象的数量依赖指针的范围),不足的地方是无法精确的满足小内存块的申请,例如1字节、2字节大小的对象,因为链表节点指针是4字节(32位平台)。
我们可以通过简单的算法避免这种情况,例如宏:
#define ALLOC_ROUNDUP(X, Y) ((X)+((Y)-1)&~((Y)-1)),我们可以采用这个宏调整block_size,使用户的对象大小保持在某个值的倍数,前面的构造函数可以修改为:
DataBlock::DataBlock(size_type block_size)
{
block_size_ = ALLOC_ROUNDUP(block_size_, 4);
base_addr_ = new unsigned char[block_size_ * MAX_BLOCKS];
/*初始化,生成链表*/
NodePtr node = head_node_ = (NodePtr)base_addr_;
head_node_->next_ = end_node();
for (size_type n = 1; n < MAX_BLOCKS; n++) {
node->next_ = (NodePtr)(base_addr_ + n*block_size_);
node = node->next_;
node->next_ = end_node();
}
}
红字部分是增加的代码,它使block_size_调整为4的倍数,这个算法也能避免字节边界的问题。
虽然通过调整block_size_使我们的内存管理器看上去适应性更强,但是如果用户对内存的需求小内存块比较多,那么我们链表方式的内存管理器会浪费更多的内存。下面的小对象内存分配方式是采用《C++设计新思维》里面的方式,在这本书里面作者采用对对象前一个字节进行添加计数的方式进行管理,一个字节最大值255,那么采用这种方式用户对象申请数量最大上限为255,下面代码摘录于《C++设计新思维》供大家参考:
struct Chunk
{
void Init(std::size_t blockSize, unsigned char blocks);
void* Allocate(std::size_t blockSize);
void Deallocate(void* p, std::size_t blockSize);
void Reset(std::size_t blockSize, unsigned char blocks);
void Release();
unsigned char* pData_;
unsigned char
firstAvailableBlock_,
blocksAvailable_;
};
Chunk::Init(std::size_t blockSize, unsigned char blocks)
{
pData_ = new unsigned char[blockSize * blocks];
Reset(blockSize, blocks);
}
Chunk::Reset(std::size_t blockSize, unsigned char blocks)
{
firstAvailableBlock_ = 0;
blocksAvailable_ = blocks;
unsigned char i = 0;
unsigned char* p = pData_;
for (; i != blocks; p += blockSize)
{
*p = ++i;
}
}
在Reset方法里面作者对申请的代码进行分段计数,它的内存分配和回收方法分别为:
Void *Chunk::Allocate(std::size_t blockSize)
{
if (!blocksAvailable_) return 0;
assert((firstAvailableBlock_ * blockSize) / blockSize ==
firstAvailableBlock_);
unsigned char* pResult =
pData_ + (firstAvailableBlock_ * blockSize);
firstAvailableBlock_ = *pResult;
--blocksAvailable_;
return pResult;
}
Void Chunk::Deallocate(void* p, std::size_t blockSize)
{
assert(p >= pData_);
unsigned char* toRelease = static_cast<unsigned char*>(p);
// Alignment check
assert((toRelease - pData_) % blockSize == 0);
*toRelease = firstAvailableBlock_;
firstAvailableBlock_ = static_cast<unsigned char>(
(toRelease - pData_) / blockSize);
// Truncation check
assert(firstAvailableBlock_ == (toRelease - pData_) / blockSize);
++blocksAvailable_;
}
《未完待续......》
我们可以通过简单的算法避免这种情况,例如宏:
#define ALLOC_ROUNDUP(X, Y) ((X)+((Y)-1)&~((Y)-1)),我们可以采用这个宏调整block_size,使用户的对象大小保持在某个值的倍数,前面的构造函数可以修改为:
DataBlock::DataBlock(size_type block_size)
{
block_size_ = ALLOC_ROUNDUP(block_size_, 4);
base_addr_ = new unsigned char[block_size_ * MAX_BLOCKS];
/*初始化,生成链表*/
NodePtr node = head_node_ = (NodePtr)base_addr_;
head_node_->next_ = end_node();
for (size_type n = 1; n < MAX_BLOCKS; n++) {
node->next_ = (NodePtr)(base_addr_ + n*block_size_);
node = node->next_;
node->next_ = end_node();
}
}
红字部分是增加的代码,它使block_size_调整为4的倍数,这个算法也能避免字节边界的问题。
虽然通过调整block_size_使我们的内存管理器看上去适应性更强,但是如果用户对内存的需求小内存块比较多,那么我们链表方式的内存管理器会浪费更多的内存。下面的小对象内存分配方式是采用《C++设计新思维》里面的方式,在这本书里面作者采用对对象前一个字节进行添加计数的方式进行管理,一个字节最大值255,那么采用这种方式用户对象申请数量最大上限为255,下面代码摘录于《C++设计新思维》供大家参考:
struct Chunk
{
void Init(std::size_t blockSize, unsigned char blocks);
void* Allocate(std::size_t blockSize);
void Deallocate(void* p, std::size_t blockSize);
void Reset(std::size_t blockSize, unsigned char blocks);
void Release();
unsigned char* pData_;
unsigned char
firstAvailableBlock_,
blocksAvailable_;
};
Chunk::Init(std::size_t blockSize, unsigned char blocks)
{
pData_ = new unsigned char[blockSize * blocks];
Reset(blockSize, blocks);
}
Chunk::Reset(std::size_t blockSize, unsigned char blocks)
{
firstAvailableBlock_ = 0;
blocksAvailable_ = blocks;
unsigned char i = 0;
unsigned char* p = pData_;
for (; i != blocks; p += blockSize)
{
*p = ++i;
}
}
在Reset方法里面作者对申请的代码进行分段计数,它的内存分配和回收方法分别为:
Void *Chunk::Allocate(std::size_t blockSize)
{
if (!blocksAvailable_) return 0;
assert((firstAvailableBlock_ * blockSize) / blockSize ==
firstAvailableBlock_);
unsigned char* pResult =
pData_ + (firstAvailableBlock_ * blockSize);
firstAvailableBlock_ = *pResult;
--blocksAvailable_;
return pResult;
}
Void Chunk::Deallocate(void* p, std::size_t blockSize)
{
assert(p >= pData_);
unsigned char* toRelease = static_cast<unsigned char*>(p);
// Alignment check
assert((toRelease - pData_) % blockSize == 0);
*toRelease = firstAvailableBlock_;
firstAvailableBlock_ = static_cast<unsigned char>(
(toRelease - pData_) / blockSize);
// Truncation check
assert(firstAvailableBlock_ == (toRelease - pData_) / blockSize);
++blocksAvailable_;
}
《未完待续......》
相关文章推荐
- 内存池模型设计探讨
- 特征提取模型系列之CNN设计
- js原生设计模式——7原型模式之new+call(this)组合应用再探讨实例
- BI项目中常见问题---模型设计
- 在PowerDesigner中设计物理模型3——视图、存储过程和函数
- 网页设计前端——盒子模型
- 基于RBAC的权限设计模型
- Justep X3中的组织模型核心设计
- HFSS 过孔模型设计向导
- CSS3-盒模型设计
- 权限模型体系设计
- 无框架架构模型探讨:简化的Java EE开发
- 浅谈12306核心模型设计思路和架构设计
- 权限系统设计2 - 概念模型和思路整理:ACL
- 在PowerDesigner中设计物理模型3——视图、存储过程和函数
- 【Spark亚太研究院系列丛书】Spark实战高手之路-第3章Spark架构设计与编程模型第3节:Spark架构设计(2)
- 基于模型设计的FPGA开发与实现:滤波器设计与实现(一)在Matlab中高效设计滤波器
- 企鹅2015校招笔试之(三)C/S模型压力算法设计实现
- MVC与三层模型探讨
- 基于模型的整车电子电气架构设计