四叉树节点的分裂与合并比较频繁,如果直接 new、delete,相对比较慢。
因此有比较做下内存优化
自己写的内存分配器,不一定够完美、或者使用者有自己的内存分配策略。
需要定义下基类,方便别人可以组装自己的内存分配器。
代码如下:
template<typename T>
class MemBase
{
public:
MemBase() {}
virtual ~MemBase() {}
virtual void* _alloc(size_t size) = 0;
virtual void _free(void* ptr) = 0;
template<typename ... Args>
inline T* New(Args... args)
{
void *ptr = _alloc(sizeof(T));
return new (ptr)T(args...);
}
inline void Delete(T* ptr)
{
ptr->~T();
_free(ptr);
}
};
继承 MemBase,并实现 _alloc、_free函数的,都可以组装到四叉树上。
四叉树定义如下:
template
class QuadTree
{
// ...(略)...
}
TAlloc
提供了组装自定义内存分配器接口
简单的new方式一些对象,并组成一个对象池的话,内存碎片会比较严重。
可以需要时,每次预先分配一大块内存。再在大块内存上,切出一个个对象地址。
这样可以比较有效的减缓内存碎片现象。
代码如下:
templateT, unsigned BlockSize = 4096>
class Blocks : public MemBase<T>
{
public:
using TMallocFunc = std::function(size_t) >;
using TFreeFunc = std::function(void*)>;
Blocks(const TMallocFunc& f1, const TFreeFunc& f2)
: mBlocks(nullptr)
, mHead(nullptr)
, mMalloc(f1)
, mFree(f2)
{
}
~Blocks()
{
while (mBlocks)
{
Item* next = mBlocks->next;
mFree(mBlocks);
mBlocks = next;
}
}
inline void* _alloc(size_t size)
{
if (!mHead)
{
newBlock();
}
void* ptr = mHead;
mHead = mHead->next;
return ptr;
}
inline void _free(void* ptr)
{
Item* p = (Item*)ptr;
p->next = mHead;
mHead = p;
}
private:
void newBlock()
{
assert(!mHead);
Item* ptr = (Item*)mMalloc(BlockSize);
if (mBlocks)
{
ptr->next = mBlocks;
mBlocks = ptr;
}
else
{
mBlocks = ptr;
mBlocks->next = 0;
}
ptr = ptr + 1;
#define PTR(N) ((Item*)((char*)ptr + (N) * sizeof(T)))
mHead = PTR(0);
size_t lstIndex = (BlockSize - sizeof(Item)) / sizeof(T) - 1;
for (size_t i = 0; i < lstIndex; i++)
{
PTR(i)->next = PTR(i + 1);
}
PTR(lstIndex)->next = nullptr;
#undef PTR
}
struct Item
{
Item* next;
};
Item* mBlocks;
Item* mHead;
TMallocFunc mMalloc;
TFreeFunc mFree;
};
对象池不够用时,继续分配块;有块组成对象池。在块上做链表,这样可以方便的得到下个对象地址。
内存对齐,让CPU可以1次获取字段数据。
代码如下:
template<typename T, unsigned BlockSize = 4096>
class Mem : public Blocks
{
public:
Mem() : Blocks(malloc, free)
{
}
~Mem()
{
}
};
template<typename T, unsigned BlockSize = 4096, unsigned Alignment = 4>
class AlignedMem : public Blocks
{
public:
#ifdef _MSC_VER
AlignedMem() : Blocks(std::bind(_aligned_malloc, std::placeholders::_1, Alignment), _aligned_free)
#else
AlignedMem() : Blocks(std::bind(aligned_alloc, Alignment, std::placeholders::_1), free)
#endif
{
}
~AlignedMem()
{
}
};
如图,new/delete的方式很慢。
内存对齐的方式最快。
据说,内存对齐的优势是在访问对象字段时,因此本测试还未完全测试出其效果。
测试代码:
https://github.com/fananchong/aoi/blob/master/tests/test1/main.cpp
本文内存分配器地址:
https://github.com/fananchong/aoi/blob/master/impl/alloc.h
内存分配相关,本人也了解不多。
比如本代码有优化改进之处,望留言指正。