Подтвердить что ты не робот

Сравнение производительности механизма распределения памяти С++ (tcmalloc vs. jemalloc)

У меня есть приложение, которое выделяет много памяти, и я рассматриваю возможность использования лучшего механизма выделения памяти, чем malloc.

Мои главные опции: jemalloc и tcmalloc. Есть ли какие-либо преимущества при использовании любого из них над другим?

Существует хорошее сравнение между некоторыми механизмами (в том числе авторским проприетарным механизмом - без блокировки) в http://locklessinc.com/benchmarks.shtml и в нем упоминаются некоторые плюсы и минусы каждого из них.

Учитывая, что оба механизма активны и постоянно совершенствуются. Кто-нибудь имеет представление или опыт относительно относительной производительности этих двух?

4b9b3361

Ответ 1

Если я правильно помню, основное отличие заключалось в многопоточных проектах.

Обе библиотеки пытаются развязать память памяти, когда потоки выбирают память из разных кешей, но у них разные стратегии:

  • jemalloc (используется Facebook) поддерживает кеш в потоке
  • tcmalloc (от Google) поддерживает пул кешей, а потоки развивают "естественную" близость к кешу, но могут меняться

Это привело, еще раз, если я правильно помню, к важной разнице в сроках управления потоками.

  • jemalloc выполняется быстрее, если потоки являются статическими, например, с помощью пулов
  • tcmalloc быстрее, когда потоки создаются/уничтожаются

Существует также проблема: поскольку jemalloc откручивает новые кеши для размещения новых идентификаторов потоков, при внезапном всплеске потоков вы оставите (в основном) пустые кеши в последующей фазе спокойствия.

В результате я бы порекомендовал tcmalloc в общем случае и зарезервировал jemalloc для очень специфических применений (низкая вариация количества потоков в течение жизни приложения).

Ответ 2

Недавно я рассмотрел tcmalloc для проекта на работе. Это то, что я наблюдал:

  • Значительно улучшена производительность при интенсивном использовании malloc в многопоточной настройке. Я использовал его с инструментом на работе, и производительность улучшилась почти в два раза. Причина в том, что в этом инструменте было несколько потоков, выполняющих выделение небольших объектов в критическом цикле. Используя glibc, производительность страдает из-за, я думаю, блокировки разрешений между malloc/free calls в разных потоках.

  • К сожалению, tcmalloc увеличивает объем памяти. Инструмент, о котором я упоминал выше, будет потреблять в два или три раза больше памяти (как измеряется максимальным размером резидентного набора). Увеличение площади - это не для нас, потому что мы действительно ищем способы уменьшить объем памяти.

В конце концов я решил не использовать tcmalloc и вместо этого оптимизировать код приложения напрямую: это означает удаление распределений из внутренних циклов, чтобы избежать недостоверности malloc/free lock. (Для любопытных, используя форму сжатия, а не используя пулы памяти.)

Урок для вас состоит в том, что вы должны тщательно измерить свое приложение с типичными рабочими нагрузками. Если вы можете позволить себе использовать дополнительную память, tcmalloc может быть для вас отличным. Если нет, tcmalloc по-прежнему полезен, чтобы узнать, что вы получите, избегая частых вызовов распределения памяти по потокам.

Ответ 3

Имейте в виду, что в соответствии с домашней страницей "nedmalloc" современные операторы выделения ОС на самом деле довольно быстро:

"Windows 7, Linux 3.x, FreeBSD 8, Mac OS X 10.6 содержат самые современные распределители, и никакой сторонний распределитель не сможет значительно улучшить их в реальных результатах"

http://www.nedprod.com/programs/portable/nedmalloc

Таким образом, вы можете уйти, просто рекомендуя обновление своих пользователей или что-то в этом роде:)

Ответ 4

Вы также можете рассмотреть возможность использования консервативного сборщика мусора Boehm. В основном, вы заменяете каждый malloc в своем исходном коде на GC_malloc (и т.д.), И вы не вызываете вызов free. Boehm GC не выделяет память быстрее, чем malloc (примерно то же самое, или может быть на 30% медленнее), но имеет то преимущество, что автоматически обрабатывает бесполезные зоны памяти, что может улучшить вашу программу (и, конечно, упрощает кодирование, так как вас больше не интересует свобода). И Boehm GC также может использоваться как распределитель С++.

Если вы действительно считаете, что malloc слишком медленный (но вы должны тестировать, большинство malloc -s занимает меньше микросекунды), и если вы полностью понимаете распределение поведения вашей программы, вы можете заменить некоторые malloc- s с вашим специальным распределителем (который мог бы, например, получить память из ядра в больших кусках, используя mmap и самостоятельно управлять памятью). Но я считаю, что это боль. В С++ у вас есть allocator и std::allocator_traits, с большинством стандартных контейнеров шаблонов, принимающих такой распределитель (см. также std::allocator), например необязательный аргумент второго шаблона для std::vector и т.д.

Как и другие, если вы считаете, что malloc является узким местом, вы можете выделить данные в кусках (или используя арены) или просто в массиве.

Иногда реализация специализированного копирования сборщика мусора (для некоторых ваших данных) может помочь. Подумайте, возможно, MPS.

Но не забывайте, что преждевременная оптимизация - это зло и, пожалуйста, сравнивайте и профаймите свое приложение, чтобы точно понять, где время потеряно.

Ответ 6

В вашем сообщении не упоминаются потоки, но перед рассмотрением смешивания методов выделения C и С++ я бы исследовал концепцию пула памяти .BOOST имеет хороший.