C++ STL с jemalloc
Как можно использовать контейнеры C++ STL с jemalloc (или любым другим malloc
реализация)?
Это так же просто, как включить jemalloc/jemalloc.h
? Или я должен написать распределитель для них?
Редактировать: приложение, над которым я работаю, распределяет и освобождает относительно небольшие объекты в течение срока его службы. Я хочу заменить распределитель по умолчанию, потому что тесты показали, что приложение не масштабируется за пределы двух ядер. Профилирование показало, что оно ожидает выделения памяти, что и вызвало проблемы с масштабированием. Насколько я понимаю, jemalloc
поможет с этим.
Я хотел бы увидеть решение, которое не зависит от платформы, так как приложение должно работать как на Linux, так и на Windows. (Связать с другой реализацией легко в Linux, но, насколько я знаю, в Windows это очень сложно.)
5 ответов
C++ позволяет заменить operator new
, Если эта замена operator new
звонки je_malloc
, затем std::allocator
косвенно позвонит je_malloc
и в свою очередь все стандартные контейнеры будут.
Это, безусловно, самый простой подход. Написание собственного распределителя требует написания всего класса. Замена malloc
может быть недостаточно (нет гарантии, что незаменимый operator new
звонки malloc
), и это имеет риски, отмеченные ранее Адрианом Маккарти
Если вы хотите заменить malloc
повсюду в вашей программе (что я хотел, а также кажется единственным логическим решением), тогда все, что вам нужно сделать, - это ссылаться на нее.
Итак, если вы используете gcc
тогда все, что вам нужно сделать, это:
g++ yourprogram.cpp -ljemalloc
Но, если это невозможно, то вы должны использовать jemalloc через другие функции, например je_malloc
а также je_free
, а затем вы должны перегрузить new
а также delete
операторы.
Нет необходимости включать какой-либо заголовок, если вы не используете специфичные для реализации функции (в основном, статистику).
Написание распределителя будет самым простым решением, так как stl был разработан, чтобы иметь взаимозаменяемые распределители. Это будет самый простой путь.
Некоторые проекты играют в игры, пытаются получить альтернативу malloc
реализация заменить malloc
а также new
Предоставляется сопутствующей библиотекой компилятора. Это подвержено всевозможным проблемам, потому что в конечном итоге вы полагаетесь на конкретные детали реализации вашего компилятора и библиотеки, которую он обычно использует. Этот путь таит в себе опасность.
Некоторые опасности попытки заменить malloc
во всем мире:
- Порядок статического инициализатора имеет ограниченные гарантии в C++. Невозможно гарантировать, что замена распределителя инициализируется до того, как первый вызывающий пользователь попытается использовать его, если только вы не запретите статические объекты, которые могут выделять память. У среды выполнения нет этой проблемы, поскольку компилятор и среда выполнения работают вместе, чтобы убедиться, что среда выполнения полностью инициализирована перед инициализацией любой статики.
- Если вы динамически ссылаетесь на библиотеку времени выполнения, то нет никакого способа гарантировать, что часть кода библиотеки времени выполнения еще не связана с ее собственной реализацией. Попытка изменить библиотеку времени выполнения компилятора может привести к проблемам с лицензированием при распространении вашего приложения.
- Все другие методы распределения не всегда могут в конечном итоге полагаться на
malloc
, Например, реализацияnew
может обойтиmalloc
для больших выделений и напрямую вызывать ОС для выделения памяти. Это требует отслеживания, чтобы убедиться, что такие распределения случайно не отправлены на заменуfree
,
Я считаю, что Chromium и Firefox заменили распределитель, но они разрабатывают некоторые грязные приемы и, вероятно, должны обновить свой подход по мере развития компилятора, компоновщика и среды выполнения.
Сделай себе распределитель. Делай так:
#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;
}
Код скопирован отсюда
Могут быть проблемы, так как конструкторы не будут вызываться. Вы можете использовать различные варианты operator new
(имеет больше возможностей, чем просто new
), который может просто выделить память без вызова конструктора или вызвать конструктор в уже выделенной памяти. http://www.cplusplus.com/reference/std/new/operator%20new%5B%5D/