割り当てられたメモリ アドレスを再利用するメモリ プール クラスと、そのクラスをラップするカスタム アロケータを使用しています。次のコード スニペットは、インターフェイスの基本的な概念を示しています。
template<class alloc>
class memory_pool
: boost::noncopyable,
public allocator_traits<void>
{
public:
memory_pool(typename alloc::size_type alloc_size);
memory_pool(typename alloc::size_type alloc_size, alloc const&);
template<typename U> memory_pool(typename alloc::size_type alloc_size,
typename alloc::rebind<U>::other const&);
virtual ~memory_pool();
pointer allocate (); /*throw(std::bad_alloc)*/
void collect ();
void deallocate(pointer) throw(); /*noexcept*/
};
pointer allocate()
{/*
Checks if a suitable chunk of memory is available in a internal linked list.
If true, then the chunk is returned and the next chunk moves up.
Otherwise, new memory is allocated by the underlying allocator.
*/}
void deallocate(pointer)
{/*
Interprets the passed pointer as a chunk of memory and stores it in a linked list.
Please note that memory isn't actually deallocated.
*/}
void collect()
{/*
Effectively deallocates the cunks in the linked list.
This will be called at least once during destruction.
*/}
確かに、このようなものの必要性は限られています。ただし、必要な状況では非常に便利です: - そのアロケーターを非常に素朴な方法で使用するクラスのアロケーター型を指定する (例: たとえそれが望ましい場合でも、より大きなピースの割り当てを回避する)。- 同じサイズのメモリの割り当てと割り当て解除を繰り返します。- アロケータを使用したい型のサイズが非常に小さい (例: char、short、int などの組み込み型)。
理論的には、実装は、実際の割り当てサイズの倍数を (基礎となるメモリ マネージャーから) 必要なたびに割り当てる memory_pool を利用できます。近接しているオブジェクトは、キャッシュやプリフェッチ アルゴリズムに適しています。私は、正しい割り当て、分割、および割り当て解除を処理するために、いくらかのオーバーヘッドを伴うこのようなメモリ プールを実装しました (ユーザーが割り当て解除に渡す各アドレスの割り当てを解除することはできません。各メモリ ブロックの先頭であるアドレスのみを割り当て解除する必要があります。以前に割り当てられている)。
次の非常に単純なコードを使用して、両方のケースをテストしました。
std::list<int, allocator<int>> list;
std::clock_t t = std::clock();
for (int i = 0; i < 1 << 16; ++i)
{
for (int j = 0; j < 1 << 16; ++j)
list.push_back(j);
list.unique();
for (int j = 0; j < 1 << 16; ++j)
list.pop_back();
}
std::cout << (std::clock() - t) / CLOCKS_PER_SEC << std::endl;
std::list
が呼び出さallocactor::allocate(1, 0)
れるたびに呼び出していpush_back
ます。unique()
各要素が触れられ、次の要素と比較されることを確認します。しかし、結果は残念でした。ブロックごとに割り当てるメモリプールを管理するために必要な最小限のオーバーヘッドは、システムが得る可能性のある利点よりも大きくなります。
パフォーマンスが向上するシナリオを考えられますか?
編集:
もちろん、よりもはるかに高速ですstd::allocator
。