How is it possible to use C++ STL containers with jemalloc (or any other malloc
implementation)?
Is it as simple as include jemalloc/jemalloc.h
There may be problems as the constructors won't be called. You may use differnt options of operator new
(has more options than just new
) which can just allocate memory without calling constructor, or call the constructor in already allocated memory. http://www.cplusplus.com/reference/std/new/operator%20new%5B%5D/
If you want to replace malloc
everywhere in your program (which I wanted to and also seems the only logical solution), then all you have to do is link against it.
So, if you use gcc
then all you have to do is:
g++ yourprogram.cpp -ljemalloc
But, if it's not possible, then you have to use jemalloc
via another functions e.g. je_malloc
and je_free
, and then you have to overload the new
and delete
operators.
There's no need for including any header if you don't use implementation-specific features (statistics, mostly).
Make yourself allocator. Do like this:
#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;
}
The code is copied from here
C++ allows you to replace operator new
. If this replacement operator new
calls je_malloc
, then std::allocator
will indirectly call je_malloc
, and in turn all standard containers will.
This is by far the simplest approach. Writing a custom allocator requires writing an entire class. Replacing malloc
may not be sufficient (there's no guarantee that the non-replaced operator new
calls malloc
), and it has the risks noted earlier by Adrian McCarthy
Writing an allocator is going to be the easiest solution, since the stl was designed to have interchangeable allocators. This will be the easiest path.
Some projects play games try to get the alternate malloc
implementation to replace the malloc
and new
s provided by the compiler's companion library. That's prone to all sorts of issues because you end up relying on specific implementation details of your compiler and the library it normally uses. This path is fraught with danger.
Some dangers of trying to replace malloc
globally:
malloc
. For example, an implementation of new
might bypass malloc
for large allocations and directly call the OS to allocate memory. That requires tracking to make sure such allocations aren't accidentally sent to the replacement free
.I believe Chromium and Firefox has both replaced the allocator, but they play some dirty tricks and probably have to update their approach as the compiler, linker, and runtime evolve.