обзор
Предыдущая статьяНастройка JVM G1 для CMSВ , мы заменили G1 на CMS и скорректировали параметры JVM, из-за более разумного выбора GC и настроек параметров рост памяти был очень медленным.
Но это не решает проблему фундаментально.Наблюдения показали, что RSS будет увеличиваться примерно на 100 миллионов в день в самое большое время, а общая тенденция по-прежнему восходящая, и нет никаких признаков падения.
анализ проблемы
Хотя рост медленный, даже если он составляет всего 1 миллион в день, выход OOM — это только вопрос времени. Это подводит нас ближе к тому, почему RSS продолжает расти.
анализ динамической памяти
В результате мониторинга было обнаружено, что память кучи периодически увеличивается и освобождается, что согласуется с нашими настройками параметров JVM, и в файле дампа не обнаружено явных проблем с бизнес-кодом.
память вне кучи
Просмотрите наши настройки параметров параметров:
-Xms2048m -Xmx2048m
-XX:+HeapDumpOnOutOfMemoryError
-XX:+CrashOnOutOfMemoryError
-XX:NativeMemoryTracking=detail
-XX:+UseConcMarkSweepGC
-XX:MetaspaceSize=256M
-XX:MaxMetaspaceSize=256M
-XX:ReservedCodeCacheSize=128m
-XX:InitialCodeCacheSize=128m
-Xss512k
-XX:+AlwaysPreTouch。
Метапространство и кодовый кеш мертвы, а в буферных пулах есть прямые буферы.
Видно, что это горизонтальная линия, и колебания отсутствуют.
Тем не менее, RSS действительно растет.В этот период Native Memory Tracking также использовался для отслеживания использования внутренней памяти JVM.В частности, это делается.
С тех пор, как мы включили NMT-XX:NativeMemoryTracking=detail
Сначала установите базовый уровень:
jcmd 1 VM.native_memory baseline
Затем выполните через некоторое время:
jcmd 1 VM.native_memory summary.diff
Посмотрите статистику в сравнении. Рисунок ниже является только примером, а конкретные цифры не для справки, потому что он был временно выполнен мной, и цифры неверны.
В реальных условиях наибольший рост приходится на классmalloc
malloc ?Это функция для применения к памяти.Зачем вам нужно применять так много? Он не выпущен? Поэтому я подумал об использовании команды pmap, чтобы посмотреть на ситуацию с отображением памяти.
Pmap предоставляет карту памяти процесса, а команда pmap используется для отображения состояния памяти одного или нескольких процессов. Он сообщает адресное пространство и информацию о состоянии памяти процесса.
Были выполнены следующие команды:
pmap -x 1 | sort -n -k3
Нашел несколько зацепок:
Есть некоторые распределения памяти около 64M и больше и больше.
glibc
Я не мог понять, поэтому погуглил. Выяснилось, что этот тип проблемы включает в себя много основных базовых знаний.Вот общий анализ.Заинтересованные читатели могут проверить для получения дополнительной информации:
В настоящее время большинство серверных программ используют ряд функций malloc/free, предоставляемых glibc, для выделения памяти.
Ранняя версия malloc в Linux была реализована Дугом Ли. У нее есть серьезная проблема, заключающаяся в том, что для выделения памяти существует только одна область выделения (арена). Каждый раз, когда память выделяется, область выделения должна быть заблокирована. Существует острая конкуренция за одновременные запросы на снятие блокировки памяти. Слово «арена» буквально означает «сцена; арена».
Так что поработайте с другой версией, разве вы не жестокая многопоточная конкуренция замков, тогда я открою еще несколько арен, ситуация с замком, естественно, улучшится.
Wolfram Gloger улучшил на основе Doug Lea, так что malloc Glibc может поддерживать многопоточность, то есть ptmalloc2. На основании только одной области распределения добавляется неосновная область распределения (неосновная арена).Основная область распределения только одна, а неосновных областей распределения может быть много.
При вызове malloc для выделения памяти он сначала проверяет, существует ли уже область распределения в частной переменной текущего потока. Если она существует, попробуйте заблокировать эту область. Если блокировка прошла успешно, эта область распределения будет использоваться для выделения памяти.
Если блокировка не удалась, это означает, что ее используют другие потоки, затем просмотрите список арен, чтобы найти незаблокированную область арены, и, если она будет найдена, используйте эту область арены для выделения памяти.
Основная область выделения может использовать brk и mmap для обращения к виртуальной памяти, а неосновная область выделения может быть только mmap. Размер блока виртуальной памяти, который glibc применяет каждый раз, составляет 64 МБ, после чего glibc разрезается на небольшие блоки для розничной продажи в соответствии с потребностями приложения.
Это типичная проблема 64 МБ в распределении памяти процесса Linux, сколько таких областей? В 64-битной системе это значение равно 8 * количество ядер,Если это 4 ядра, имеется до 32 областей памяти размером 64 МБ..
glibc ввел пул памяти для каждого потока с версии 2.11, а мы используем версию 2.17.Вы можете запросить номер версии с помощью следующей команды
# 查看 glibc 版本
ldd --version
задача решена
Максимальное количество арен можно контролировать параметром MALLOC_ARENA_MAX на сервере.
export MALLOC_ARENA_MAX=1
Так как мы используем docker-контейнер, он добавляется в параметры запуска docker.
После перезапуска контейнера обнаружилось отсутствие выделения памяти 64M.
Но RSS все еще растет, хотя на этот раз более медленными темпами. Так что снова гуглите. (На самом деле эффективно наблюдать в других средах в течение длительного времени после этого, хотя в краткосрочной перспективе наблюдается рост, позже будет спад.)
Запрос может быть связан с проблемой выделения фрагментированной памяти, вызванной стратегией выделения памяти glibc, которая выглядит как утечка памяти. Есть ли лучшая библиотека malloc для фрагментированной памяти? Наиболее распространенными в отрасли являются tcmalloc от Google и jemalloc от Facebook.
tcmalloc
Установить
yum install gperftools-libs.x86_64
Монтировать с LD_PRELOAD
export LD_PRELOAD="/usr/lib64/libtcmalloc.so.4.4.5"
Обратите внимание, что java-приложение необходимо перезапустить.После моего теста с использованием tcmalloc память RSS все еще увеличивается, что недопустимо для меня.
jemalloc
Установить
yum install epel-release -y
yum install jemalloc -y
Монтировать с LD_PRELOAD
export LD_PRELOAD="/usr/lib64/libjemalloc.so.1"
После использования jemalloc память RSS периодически колеблется, и диапазон колебаний составляет около 2%, что в основном контролируется.
принцип жемаллока
Подобно tcmalloc, каждый поток также использует локальный кеш потока без блокировок, если размер меньше 32 КБ.
Jemalloc использует следующие классы размеров в 64-битных системах:
- Маленькие: [8], [16, 32, 48, …, 128], [192, 256, 320, …, 512], [768, 1024, 1280, …, 3840]
- Большой: [4 КиБ, 8 КиБ, 12 КиБ, …, 4072 КиБ]
- Огромный: [4 МБ, 8 МБ, 12 МБ, …]
Маленьким/большим объектам требуется постоянное время для поиска метаданных, огромные объекты ищут логарифмически через глобальное красно-черное дерево.
Виртуальная память логически разделена на чанки (по умолчанию 4 МБ, 1024 страницы по 4 КБ).Поток приложения выделяет арену на первом malloc с помощью алгоритма циклического перебора. Каждая арена независима друг от друга и поддерживает свои собственные чанки. разрезает страницы на маленькие/большие объекты. Память Free() всегда возвращается в область владения, независимо от того, какой поток вызвал free().
На приведенном выше рисунке вы можете увидеть структуру фрагмента арены, управляемую каждой ареной.Заголовок в начале в основном поддерживает карту страниц (статус объекта, связанный с 1024 страницами), а его страничное пространство находится под заголовком. Небольшие объекты группируются вместе, а информация о метаданных сохраняется в начале. Большие фрагменты не зависят друг от друга, а их метаданные хранятся в карте заголовка фрагмента.
При распределении через арену необходимо заблокировать корзину арены (по одной на каждый малый размерный класс, мелкозернистую) или заблокировать саму арену. И объект кэша потока также будет возвращен на арену с помощью алгоритма экспоненциальной отсрочки сборки мусора.
jemalloc сравнение tcmalloc
На приведенном выше рисунке приведены сравнительные данные пропускной способности сервера, достигнутой с помощью 6 malloc соответственно.Вы можете видеть, что tcmalloc и jemalloc являются лучшими (результаты тестирования Facebook в 2011 году, tcmalloc — более старая версия здесь).
Подводя итог: эффект от использования tcmalloc и jemalloc в многопоточной среде очень очевиден. Когда количество потоков фиксировано и не будет часто создаваться и закрываться, можно использовать jemalloc; в противном случае лучшим выбором может быть tcmalloc.
Суммировать
Если вы заметите, что в памяти много таких выделений по 64 м, возможно, вы наступили на эту яму, тогда вы можете изменить MALLOC_ARENA_MAX и терпеливо наблюдать, если нет, попробуйте использовать jemalloc или tcmalloc