Сравнение производительности механизма распределения памяти С++ (tcmalloc vs. jemalloc)
У меня есть приложение, которое выделяет много памяти, и я рассматриваю возможность использования лучшего механизма выделения памяти, чем malloc.
Мои главные опции: jemalloc и tcmalloc. Есть ли какие-либо преимущества при использовании любого из них над другим?
Существует хорошее сравнение между некоторыми механизмами (в том числе авторским проприетарным механизмом - без блокировки) в http://locklessinc.com/benchmarks.shtml
и в нем упоминаются некоторые плюсы и минусы каждого из них.
Учитывая, что оба механизма активны и постоянно совершенствуются. Кто-нибудь имеет представление или опыт относительно относительной производительности этих двух?
Ответы
Ответ 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.
Но не забывайте, что преждевременная оптимизация - это зло и, пожалуйста, сравнивайте и профаймите свое приложение, чтобы точно понять, где время потеряно.
Ответ 5
Здесь есть довольно неплохие обсуждения о распределителях:
http://www.reddit.com/r/programming/comments/7o8d9/tcmalloca_faster_malloc_than_glibcs_open_sourced/
Ответ 6
В вашем сообщении не упоминаются потоки, но перед рассмотрением смешивания методов выделения C и С++ я бы исследовал концепцию пула памяти .BOOST имеет хороший.