2012-03-01 4 views
10

jemalloc(または他のmalloc実装)でC++ STLコンテナを使用するにはどうすればよいですか?jemallocを使用したC++ STL

jemalloc/jemalloc.hと同じくらい簡単ですか?または私はそれらのためのアロケータを書く必要がありますか?

編集:私が取り組んでいるアプリケーションは、比較的寿命の短いオブジェクトを割り当てて解放します。ベンチマークでは、アプリケーションが2つのコアを超えて拡張されていないことが示されているので、デフォルトのアロケータを置き換えてください。プロファイリングではメモリ割り当てを待っていることが判明し、スケ​​ーリングの問題が発生しました。私が理解するように、jemallocがそれを助けるでしょう。アプリケーションは、LinuxとWindowsの両方で動作するように持っているよう


私は解決策を見てみたいと思いますが、それはプラットフォームに依存します。 (Linuxでは異なる実装とリンクするのは簡単ですが、私が知る限り、Windowsでは非常に難しいです。)

答えて

6

は、operator newを置き換えることができます。この交換品operator newje_mallocを呼び出す場合、std::allocatorは間接的にje_mallocを呼び出し、すべての標準コンテナになります。

これははるかに簡単なアプローチです。カスタムアロケータを書くには、クラス全体を書く必要があります。 mallocを交換する(operator new通話mallocを非置き換えるという保証はありません)で十分であり、それはエイドリアン・マッカーシー

1

コンストラクタが呼び出されないため、問題が発生することがあります。 operator newのdifferntオプションを使用することもできます(単にnew以上のオプションがあります)。コンストラクタを呼び出さずにメモリを割り当てたり、すでに割り当てられたメモリにコンストラクタを呼び出したりすることができます。 http://www.cplusplus.com/reference/std/new/operator%20new%5B%5D/

3

stlは互換性のあるアロケータを持つように設計されているため、アロケータを書くのが最も簡単な解決策になります。これは最も簡単な方法です。

一部のプロジェクトでは、mallocおよびnewの代わりに、mallocの代替プログラムを取得しようとしています。コンパイラのコンパニオンライブラリが提供しています。これは、コンパイラやそれが通常使用するライブラリの具体的な実装の詳細に頼ることになるので、あらゆる種類の問題になりがちです。この道は危険に満ちている。グローバルmallocを交換しようとしているの

いくつかの危険性:

  • 静的初期化子の順序は、C++での保証を制限しています。メモリを割り当てる可能性のある静的オブジェクトを禁止しない限り、最初の呼び出し元がそれを使用しようとする前に、アロケータ置換が初期化されることを保証する方法はありません。ランタイムは完全に初期化される前に、コンパイラとランタイムが連携して動作するため、この問題は発生しません。
  • ランタイムライブラリに動的にリンクする場合、ランタイムライブラリのコードの一部が独自の実装にバインドされていないことを確認する方法はありません。コンパイラのランタイムライブラリを変更しようとすると、アプリケーションを再配布する際にライセンスの問題が発生する可能性があります。
  • 他のすべての割り当て方法は、最終的にはmallocに依存するとは限りません。たとえば、newの実装では、大きな割り当ての場合はmallocをバイパスし、メモリを割り当てるためにOSを直接呼び出すことがあります。そのような割り当てが誤って交換先freeに送信されないように追跡する必要があります。

私はクロムとFirefoxの両方がアロケータを交換していると考えているが、彼らはいくつかの汚いトリックを再生すると、おそらく、コンパイラ、リンカ、およびランタイム進化としてのアプローチを更新する必要があります。

+0

からコピーされます。 'new'の代わりにどのような問題がありますか? – KovBal

+0

'new'を通常のC++の俗語で置き換えようとしているのであれば、手に入れることができます。それは本当に毛深くなるプログラム全体を通して 'malloc'を置き換えることを試みる時です。 –

+0

これはまさに私がやりたいことです:プログラム全体を通して 'malloc'を置き換えてください。しかし私は自分の実装を書いてはいけません。私は別の(よくテストされた)ものを使いたいだけです。 – KovBal

6

mallocをプログラムのどこに置きたいのか(これは私が欲しかったのですが、唯一の論理的解決策にも見えるでしょう)、それにリンクするだけです。

あなたがgccを使用するのであれば、あなたがしなければならないすべては次のとおりです。

g++ yourprogram.cpp -ljemalloc 

しかし、それは不可能です場合は、例えば、別の機能を経由してjemalloc使用する必要がありますje_mallocje_freeを入力してから、newdelete演算子をオーバーロードする必要があります。

実装固有の機能(ほとんどの統計情報)を使用しない場合は、ヘッダーを含める必要はありません。

1

によって前述のリスクは自分でアロケータを作成していないかもしれません。このように行います。

#include <vector> 

template<typename T> 
struct RemoveConst 
{ 
    typedef T value_type; 
}; 

template<typename T> 
struct RemoveConst<const T> 
{ 
    typedef T value_type; 
}; 

template <class T> 
class YourAlloc { 
public: 
    // type definitions 
    typedef RemoveConst<T>    Base; 
    typedef typename Base::value_type value_type; 
    typedef value_type*     pointer; 
    typedef const value_type*   const_pointer; 
    typedef value_type&     reference; 
    typedef const value_type&   const_reference; 
    typedef std::size_t     size_type; 
    typedef std::ptrdiff_t    difference_type; 

    // rebind allocator to type U 
    template <class U> 
    struct rebind { 
     typedef YourAlloc<U> other; 
    }; 

    // return address of values 
    pointer address(reference value) const { 
     return &value; 
    } 
    const_pointer address(const_reference value) const { 
     return &value; 
    } 

    /* constructors and destructor 
    * - nothing to do because the allocator has no state 
    */ 
    YourAlloc() throw() { 
    } 
    YourAlloc(const YourAlloc&) throw() { 
    } 
    template <class U> 
    YourAlloc(const YourAlloc<U>&) throw() { 
    } 
    ~YourAlloc() throw() { 
    } 

    // return maximum number of elements that can be allocated 
    size_type max_size() const throw() { 
     return std::numeric_limits<std::size_t>::max()/sizeof(T); 
    } 

    // allocate but don't initialize num elements of type T 
    pointer allocate(size_type num, const void* = 0) { 
     return (pointer)je_malloc(num * sizeof(T)); 
    } 

    // initialize elements of allocated storage p with value value 
    void construct(pointer p, const T& value) { 
     // initialize memory with placement new 
     new((void*)p)T(value); 
    } 

    // destroy elements of initialized storage p 
    void destroy(pointer p) { 
     // destroy objects by calling their destructor 
     p->~T(); 
    } 

    // deallocate storage p of deleted elements 
    void deallocate(pointer p, size_type num) { 
     je_free(p); 
    } 
}; 

// return that all specializations of this allocator are interchangeable 
template <class T1, class T2> 
bool operator== (const YourAlloc<T1>&, 
    const YourAlloc<T2>&) throw() { 
    return true; 
} 
template <class T1, class T2> 
bool operator!= (const YourAlloc<T1>&, 
    const YourAlloc<T2>&) throw() { 
    return false; 
} 

int main() 
{ 
    std::vector<int, YourAlloc<int>> vector; 

    return 0; 
} 

コードは、私はあなたのに答えるために私の質問を更新しhere

+0

アロケータが良いアイデアかもしれません。大部分のデータがアロケータ対応コンテナに格納されている場合は、非常に良い解決策です。 – KovBal

関連する問題