如何使用带有jemalloc(或任何其他malloc
实现)的C ++ STL容器?
是否像include jemalloc/jemalloc.h
一样简单?或者我应该为他们写一个分配器?
编辑:我正在处理的应用程序在其生命周期内分配和释放相对较小的对象。我想替换默认的分配器,因为基准测试显示应用程序不会超过2个核心。分析显示它正在等待内存分配,这就是导致扩展问题的原因。据我了解,jemalloc
将有助于此。
我希望看到一个解决方案,这是平台中立的,因为应用程序必须在Linux和Windows上运行。 (在Linux下链接不同的实现很容易,但据我所知,在Windows上这很难实现。)
答案 0 :(得分:8)
C ++允许您替换 operator new
。如果此替换operator new
调用je_malloc
,则std::allocator
会间接调用je_malloc
,反过来所有标准容器都会调用。
这是迄今为止最简单的方法。编写自定义分配器需要编写整个类。替换malloc
可能还不够(无法保证未替换的operator new
调用malloc
),并且它具有Adrian McCarthy先前提到的风险
答案 1 :(得分:6)
如果你想在程序的任何地方替换malloc
(我想要的,也似乎是唯一的逻辑解决方案),那么你所要做的就是链接它。
因此,如果您使用gcc
,那么您所要做的就是:
g++ yourprogram.cpp -ljemalloc
但是,如果不可能,那么你必须通过其他功能使用jemalloc,例如je_malloc
和je_free
,然后您必须重载new
和delete
运算符。
如果您不使用特定于实现的功能(主要是统计信息),则无需包含任何标头。
答案 2 :(得分:3)
编写分配器将是最简单的解决方案,因为stl旨在具有可互换的分配器。这将是最简单的途径。
某些项目玩游戏尝试使用备用malloc
实现来替换编译器的伴随库提供的malloc
和new
。这容易出现各种各样的问题,因为您最终依赖于编译器的特定实现细节以及它通常使用的库。这条道路充满了危险。
尝试全局替换malloc
的一些危险:
malloc
。例如,new
的实现可能会绕过malloc
进行大量分配,并直接调用操作系统来分配内存。这需要跟踪以确保不会意外地将此类分配发送到替换free
。我相信Chromium和Firefox都取代了分配器,但是他们发挥了一些肮脏的技巧,可能不得不随着编译器,链接器和运行时的发展而更新他们的方法。
答案 3 :(得分:1)
可能存在问题,因为构造函数不会被调用。您可以使用operator new
的不同选项(除了new
之外有更多选项),它们可以在不调用构造函数的情况下分配内存,或者在已分配的内存中调用构造函数。 http://www.cplusplus.com/reference/std/new/operator%20new%5B%5D/
答案 4 :(得分: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
复制的