9

私は注文するために類似のタイプのオブジェクトを多数作成しているパフォーマンスクリティカルなアプリケーションを書いています。メモリの割り当てにboost::singleton_poolを使用しています。最後に、私のクラスは次のようになります。

    class MyOrder{
    std::vector<int> v1_;
    std::vector<double> v2_;

    std::string s1_;
    std::string s2_;

public:
    MyOrder(const std::string &s1, const std::string &s2): s1_(s1), s2_(s2) {}

    ~MyOrder(){}

    static void * operator new(size_t size); 
    static void operator delete(void * rawMemory) throw();
    static void operator delete(void * rawMemory, std::size_t size) throw();

};

struct MyOrderTag{};
typedef boost::singleton_pool<MyOrderTag, sizeof(MyOrder)> MyOrderPool; 

void* MyOrder:: operator new(size_t size)
{
    if (size != sizeof(MyOrder)) 
        return ::operator new(size);

    while(true){
        void * ptr = MyOrderPool::malloc();
        if (ptr != NULL) return ptr;

        std::new_handler globalNewHandler = std::set_new_handler(0);
        std::set_new_handler(globalNewHandler);

        if(globalNewHandler)  globalNewHandler();
        else throw std::bad_alloc();

    }
}

void MyOrder::operator delete(void * rawMemory) throw()
{
    if(rawMemory == 0) return; 
    MyOrderPool::free(rawMemory);
}

void MyOrder::operator delete(void * rawMemory, std::size_t size) throw()
{
    if(rawMemory == 0) return;
    if(size != sizeof(Order)) {
        ::operator delete(rawMemory);
    }
    MyOrderPool::free(rawMemory);
}

最近、 boost::singleton_pool を使用した場合のパフォーマンス上の利点について質問を投稿しました。boost::singleton_poolとデフォルト アロケータのパフォーマンスを比較したところ、パフォーマンス上の利点は得られませんでした。私のクラスに std::string 型のメンバーがあり、その割り当てがカスタム アロケーターによって管理されていないことを誰かが指摘したとき、私は std::string 変数を削除し、テストを再実行しました。今回は、かなりのパフォーマンスの向上に気付きました。

  1. さて、私の実際のアプリケーションでは、時刻 std::string と std::vector のメンバー変数を取り除くことができません。std::string および std::vector メンバー変数でboost::pool_allocatorを使用する必要がありますか?

  2. boost::pool_allocator は、基礎となる std::singleton_pool からメモリを割り当てます。メンバー変数が異なるかどうかは問題になりますか (MyOrder クラスに複数の std::string/std::vector 型があります。また、std::string/std::vector 型を含む MyOrder 以外のクラスにプールを使用しています)メンバーとしても) 同じメモリ プールを使用しますか? もしそうなら、どうすれば彼らがどちらかの方法で行うことを確認できますか?

4

2 に答える 2

2
  1. さて、私の実際のアプリケーションでは、時刻 std::string と std::vector のメンバー変数を取り除くことができません。std::string および std::vector メンバー変数で boost::pool_allocator を使用する必要がありますか?

ブーストのその部分を調べたことはありませんが、文字列がメモリを割り当てる場所を変更したい場合は、std::basic_string<>コンパイル時に別のアロケータを渡す必要があります。他に方法はありません。ただし、その欠点に注意する必要があります。たとえば、そのような文字列は割り当てられstd::stringなくなります。(使用してc_str()も機能しますが、パフォーマンスがわずかに低下する可能性があります。)

  1. boost::pool_allocator は、基礎となる std::singleton_pool からメモリを割り当てます。メンバー変数が異なるかどうかは問題になりますか (MyOrder クラスに複数の std::string/std::vector 型があります。また、std::string/std::vector 型を含む MyOrder 以外のクラスにプールを使用しています)メンバーとしても) 同じメモリ プールを使用しますか? もしそうなら、どうすれば彼らがどちらかの方法で行うことを確認できますか?

プールの要点は、複数のオブジェクトをプールに入れることです。1つだけだったら、プールは必要ありません。したがって、いくつかのオブジェクトの動的メモリを含め、いくつかのオブジェクトをその中に入れることができstd::stringます。

ただし、これによりパフォーマンスが向上するかどうかはまだわかりません. プールを使用するのは、汎用アロケータよりも高速であると想定する理由があるためです (たとえば、共有メモリなどの特定の領域からメモリを割り当てるために使用するのではなく)。通常、このようなプールは、割り当てられたオブジェクトのサイズを想定できるため、より高速です。それは確かにあなたのMyOrderクラスに当てはまります。そのオブジェクトは常に同じサイズです。それ以外の場合 (より大きな派生クラス)、それらをプールに割り当てません。
それは違うstd::string. 動的に割り当てる文字列クラスを使用するポイントは、文字列の長さに適応することです。そのために必要なメモリ チャンクのサイズは異なります (それ以外の場合は、代わりに char 配列を使用できます)。そのために、プール アロケータが汎用アロケータを改善する余地はほとんどないと思います。


補足: あなたのオーバーロードoperator new()は、グローバルなものを呼び出した結果を返しますが、operator deleteそのプールのfree(). それは私には非常に疑わしいようです。

于 2012-05-08T19:43:16.903 に答える
1

std::stringクラスの/にカスタムアロケータを使用するstd::vectorことは機能します(アロケータが正しいと仮定します)-しかし、パフォーマンステストのみが、それから実際に何らかの利点が見られるかどうかを確認します。

std::stringまたは、 /std::vectorに上限があることがわかっている場合は、 std::array(またはc ++ 11がない場合は通常の配列)の周りに薄いラッパーを実装して、置換をドロップすることができます。

サイズに制限がない場合でも、ほとんどの値が小さくなるサイズがある場合はstd::array、プールされたアロケータがいっぱいになった場合に割り当てることで、上記のベースの実装を拡張可能に拡張できます。

于 2012-05-17T18:54:20.417 に答える