- How do I monitor the computer’s CPU, memory, and disk usage in Java?
- Скахин Алексей / pihel
- Страницы
- четверг, 21 ноября 2019 г.
- Настройка и мониторинг производительности Java приложений
- Состав кучи
- Параметры настройки
- Виды сборщиков мусора
- Serial
- Parallel
- Parallel Old
- Concurrent Mark-Sweep
- GC в Hive
- Комманды для мониторинга Java из консоли
- PrintCommandLineFlags
- Verbose: gc
- HeapDumpOnOutOfMemoryError
- JSTAT
- VisualVM
- Flight Recorder
- Mission Control
- Мониторинг OS
- Flame Graph
- Оптимизация работы с памятью в программах
- Особенности JVM IBM AIX
How do I monitor the computer’s CPU, memory, and disk usage in Java?
I would like to monitor the following system information in Java:
- Current CPU usage** (percent)
- Available memory* (free/total)
Available disk space (free/total)
*Note that I mean overall memory available to the whole system, not just the JVM.
I’m looking for a cross-platform solution (Linux, Mac, and Windows) that doesn’t rely on my own code calling external programs or using JNI. Although these are viable options, I would prefer not to maintain OS-specific code myself if someone already has a better solution.
If there’s a free library out there that does this in a reliable, cross-platform manner, that would be great (even if it makes external calls or uses native code itself).
Any suggestions are much appreciated.
To clarify, I would like to get the current CPU usage for the whole system, not just the Java process(es).
The SIGAR API provides all the functionality I’m looking for in one package, so it’s the best answer to my question so far. However, due it being licensed under the GPL, I cannot use it for my original purpose (a closed source, commercial product). It’s possible that Hyperic may license SIGAR for commercial use, but I haven’t looked into it. For my GPL projects, I will definitely consider SIGAR in the future.
For my current needs, I’m leaning towards the following:
- For CPU usage, OperatingSystemMXBean.getSystemLoadAverage() / OperatingSystemMXBean.getAvailableProcessors() (load average per cpu)
- For memory, OperatingSystemMXBean.getTotalPhysicalMemorySize() and OperatingSystemMXBean.getFreePhysicalMemorySize()
- For disk space, File.getTotalSpace() and File.getUsableSpace()
The getSystemLoadAverage() and disk space querying methods are only available under Java 6. Also, some JMX functionality may not be available to all platforms (i.e. it’s been reported that getSystemLoadAverage() returns -1 on Windows).
Although originally licensed under GPL, it has been changed to Apache 2.0, which can generally be used for closed source, commercial products.
Скахин Алексей / pihel
Личный блог. Заметки о программировании и не только
Страницы
четверг, 21 ноября 2019 г.
Настройка и мониторинг производительности Java приложений
Состав кучи
Java Heap разделена на 3 основные части:
- Область Yang
- Survivor (выжившие)
Если на объект имеются ссылки, то он перемещается из Eden в S0 Survivor
При этом счетчик числа GC у объекта инкрементируется.
Объекты без ссылок, удаляются из Eden.- S0 (From) Когда Eden снова заполняется полностью, снова срабатывает Minor GC
Теперь он затрагивает области Eden и Survivor
— Объекты без ссылок удаляются из Eden и Survivor
— Используемые объекты из S0 и Eden перемещаются в S1 и инкрементируется счетчик - S1 (To) После второго Minor GC куча выглядит так:
- S0 (From) Когда Eden снова заполняется полностью, снова срабатывает Minor GC
- Eden
Все объекты изначально попадают в эту область.
Когда Eden полностью заполняется, срабатывает Minor GC только над областью Yang
Minor GC всегда происходит с остановкой основного цикла программы (Stop-the-word), но за счет небольшого размера области, сборка происходит быстро.
После InitialTenuringThreshold операций Minor GC (по умолчанию = 7 ) объект перестает считаться Yang и переносится из области Survivor в постоянную область Old (Tenured)
— Объем Old области больше, чем Yang (обычно в NewRatio раз = 2) и наполняется медленней
— Full GC по Old области редки, но достаточно продолжительны
— Цель настройки объектов программы и GC — минимизировать число Full GC
Область Permanent фиксирован по размеру и почти не растет во время работы.
Внутри ее содержится данные о метаданных и классах.
Параметры настройки
Названия основных параметров:
Просмотреть список всех параметров: Если параметр объявлен с «=» , то это значение по умолчанию.
Если с «:=» , то параметр был переопределен.
Полное описание всех параметров на сайте oracle.
Значения, выставляемые по умолчанию:
* Для серверного ПК:
— Parallel (Throutput) collector
— Xms (начальный размер Heap) = 1/64 доступной памяти
— Xmx (максимальный размер Heap) = 1/4 памяти
* Для прочих устройств:
— Serial gc
— Xm* параметры такиеже
Вариант оптимизации: устанавливать Xms = Xmx, чтобы ускорить работу программы, за счет уменьшения числа изменений объема памяти
Виды сборщиков мусора
Serial
Parallel
Parallel Old
Такой же как «Parallel», но Old GC выполняется параллельно, что еще добавляет пропускной способности.
Над Old областью также происходит дефрагментация данных, что упрощает поиск свободных мест для будущих объектов:
Над Yang областью не надо проводить дефргаментацию, т.к. она заполняется перемещением между S0 и S1.
Concurrent Mark-Sweep
Этот коллектор используется по умолчанию в серверных приложениях.
По принципу работы G1 схож с CMS, но имеет ряд преимуществ:
* Выполняется конкурентно как CMS gc
* Память дефрагментируется без остановки основного цикла программы
* Фиксированный (предсказуемый) размер паузы gc
* Пропускная способность остается достаточно высокой
* Не требует дополнительных 20% озу, как CMS gc (но все равно нужны 10% = G1ReservePercent)
Достигается это за счет того, что вся память делится на 2048 регионов (-XX:G1HeapRegionSize) от 1 до 32 МБ (в зависимости от размера кучи).
Выжившие объекты копируются из своего региона в свободный (дефрагментация), этот процесс дискретный и может быть остановлен в любой момент (фиксированная пауза)
Желатльно чтобы размер объекта был от 50-100% размера региона. Если объект больше региона, то он будет хранится в смежных регионах, что может вызывать задержки при обработке.
Параметры коллектора, на которые стоит обратить внимание:
-XX:MaxGCPauseMillis=200
Ставьте этот параметр = 90% от необходимого времени отклика
-XX:ConcGCThreads
кол-во процессов параллельной обработки регионов
-XX:InitiatingHeapOccupancyPercent=45
заполненность heap, после которой начинается gc
-XX:G1ReservePercent=10
резерв памяти, для защиты от переполнения
Полный список параметров и их описание на сайте oracle
GC в Hive
В сборке Hadoop от Hortonworks используется G1 gc для Hive
Сменить GC можно, только с перезапуском сервиса.
В виду сложности этой операции, проведем тесты с параметрыми G1, которые можно менять прямо во время выполнения запроса.
Databricks провела тесты сравнения нескольких коллекторов и их параметров.
По результату исследования был сделан вывод:
* Лучший коллектор для hadoop — G1
* Уменьшить % заполняемости heap (InitiatingHeapOccupancyPercent), чтобы gc происходил раньше, что должно уменьшить число долгих full gc
* Увеличить число параллельных потоков gc (ConcGCThreads) — это увеличит нагрузку на CPU, но ускорит GC
Протестируем параметры gc на запросе с distinct, чтобы был создан большой хэш массив и сортировок со слиянием.
1. Запуск с параметрами по умолчанию: Время GC = 364 407 мс.
Полный список параметров GC во время работы:
2. Изменим параметры G1: увеличим число потоков (ConcGCThreads) и установим % памяти на котором будет срабатывать GC на 35 (InitiatingHeapOccupancyPercent) Повторим тотже запрос: Время GC = 382 224 мс. Не смотря на рекомендации, время GC увеличилось.
Для себя сделал вывод — нет смысла трогать параметры GC в большинстве случаев, если нет явных проблем при сборке мусора.
Комманды для мониторинга Java из консоли
PrintCommandLineFlags
Verbose: gc
Выводить в консоль подробную информацию о работе GC
* GC — minor gc над yang областью
* Full GC — поный gc над Old областью
[Тип GC heap_до -> после (общий размер heap), время_gc]
Дополнительные параметры verbose:gc
* PrintGCTimeStamps — время в секундах с момента старта программы
* PrintGCDetails — дополнительная информация о затратах CPU
* PrintGCApplicationsStoppedTime — время работы GC с остановкой программы
* PrintGCApplicationsConcurrentTime — время на конкурентную работу GC
HeapDumpOnOutOfMemoryError
команда | Описание |
help | Список этих параметров |
JFR.start | Стартовать запись Java Flight Recorder |
JFR.stop | Остановить запись Java Flight Recorder |
JFR.dump | Сохранить запись Java Flight Recorder |
JFR.check | Проверка — включен ли Java Flight Recorder? |
VM.native_memory | |
VM.check_commercial_features | Проверка включенности коммерческих возможностей |
VM.unlock_commercial_features | Включить комерческие возможности VM |
ManagementAgent.stop | |
ManagementAgent.start_local | |
ManagementAgent.start | |
Thread.print | Получить stacktrace всех потоков. Удобно, если приложение зависло с блокировкой, для определения проблемного места. |
GC.class_stats | |
GC.class_histogram | |
GC.heap_dump | Сделать дамп heap для анализа в VisualVM |
GC.run_finalization | |
GC.run | Выполнить GC |
VM.uptime | Время работы приложения |
VM.flags | |
VM.system_properties | |
VM.command_line | |
VM.version | Версия java |
JSTAT
Консольная утилита для мониторинга GC 1000 — это период обновления монитора
YGC — число срабатываний Yang GC
YGCT — время работы Yang GC
FGC — число срабатываний Full GC
FGCT — время работы Full GC
GCT — общее время GC
S0, S1, E (eden), O (Full) — % утилизации областей Heap
VisualVM
Удобное бесплатное приложение от Oracle для анализа Java приложений.
VisualVM расширяется за счет plugins. Основные, которыми рекомендую пользоваться:
Overview — общие параметры jvm
Visual GC — online визуализация и история работы GC в разрезе областей heap
Sampler — информация о нагрузке на CPU и объеме объектов.
Замеры происходят с некоторой периодичностью раз в несколько мс, что обеспечивает минимальную нагрузку на приложение, но дает не 100% правильную картину.
Распределение времени CPU по методам приложения:
Топ объектов по памяти, без привязки к методам:
Но тут же можно снять heap dump и узнать реальную картину распредления памяти по методам и объектам:
Если это оконное java приложение, то сэмплировать можно выбранную часть окна:
Профилирование
Профилировщик явно трассирует работу программы, что дает наиболее верный резальтат в сравнении с сэмплированием.
Для того, чтобы начать трассировать программу, нужно запустить ее с особенными параметрами: После чего к запущенному приложению можно подключиться для анализа из visualvm.
При запуске можно указать фильтр на определенный класс приложения.
В отличие от сэплирования, при трассировке, объем объектов можно анализировать в разрезе методов:
Так же можно анализировать исходящие JDBC запросы:
Распределение времени CPU:
Flight Recorder
Mission Control
Приложение для анализа трассировок записанных Flight Recorder (.jfr)
Общая информация о системных показателях: CPU, Memory:
Топ объектов в heap (можно получить и разрез по методам):
Распределение времени по объектам:
Но, похоже, статистики по JDBC нет.
Мониторинг OS
Мониторинг CPU, ОЗУ * Procs
r: число процессов ожидающих выполнение
b: число спящих процессов
* Memory
swpd: зарезервировано виртуальной памяти
free: свободной памяти
buff: памяти для буферов
cache: памяти под кэш
* Swap
si: памяти загруженной в озу с диска / сек
so: памяти выгруженной на диск / сек
* IO
bi: число считанных блоков / сек
bo: число записанных блоков / сек
* System
in: плановая смена контекста на новый поток
cs: внеплановая смена контекста, когда потом с большим приоритетом вытесняет низкоприоритетный
* % общего времени CPU
us: время за работой программ
sy: время работы ОС. Большой % тут означает большое число блокировок при доступе к ресурсам.
id: Время Idle
wa: время ожидания IO
st: Время виртуализации
Top CPU процессов
включая строку запуска процесса Потоки процесса
Получить список потоков, отсортированных по потреблению CPU: В 4 столбце «LWP» находится ID потока.
Если сделать theatdump процесса через jstack, то можно найти проблемный поток, который грузит CPU.
Для этого LWP нужно преобразовать из десятичной системы в шестнадцатеритную и найти поток с этим nid (0x3d4a == 15690)
Nethogs — Топ процессов по использованию сети
IOTOP — Топ процессов по использованию IO
Flame Graph
Flame graph удобный инструмент для визуализации полного стека вызовов linux процессов.
По оси X — время работы вызова, по оси Y — стек, цветом обозначается область: красное — ядро, другие цвета — язык.
Пример визуализации для Oracle можно видеть тут
Я бы хотел показать как создать Flame Graph для Java приложения, т.к. есть особенности:
1. JVM должна быть запущена с флагом «-XX:+PreserveFramePointer», который поддерживается с JDK 8u60
2. Нужно скачать и скомпилировать утилиту perf-map-agent
Она нужна, чтобы получить читаемые названия функций.
3. Скачать Perl скрипты FlameGraph
4. Установить пакет perf в Linux
Пример запуска Spark с параметром PreserveFramePointer Запуск Hive с параметром PreserveFramePointer Далее запускаем проблемный запрос в Hive/Spark.
Подключаемся по ssh к одной из нод кластера.
Ищем нужные процессы с запросом (см. п. Мониторинг OS)
Выполняем perf-map-agent, perf и FlameGraph для процесса $1 Скрипт 60 секунд собирает метрики по процессу и по итогу формируется Flame Graph perf-kernel.svg:
* Зеленым — работа нашей java программы (в данном случае hive)
* Красное — вызовы ядра
Как минимум по этому графику видно:
1. по оси X нет долгих красных промежутков в конце стека (верхняя часть графика), т.е. процесс выполнял полезную работу, а не тратил время на GC
2. Последовательные зеленые участки — чтение данных с диска — «org/apache/hadoop/hive/serde2/io/HiveDecimalWritable. getHiveDecimal». Т.е. зависаний на определенном чтений нет нет и данные перебираются успешно
Примеры полных FlameGraph для Hive и Spark
Оптимизация работы с памятью в программах
Слабые ссылки
Слабые ссылки могут очищаться GC, даже если на них есть другие ссылки в программе.
Удобно использовать для кэша — даже если объект пропадет из памяти, его всегда можно восстановить.
* SoftReference — объект будет удален, если JVM очень нужна память и на объект только слабые ссылки
* WeakReference — объект будет удален, если на объект только слабые ссылки
* PhantomReference — могут быть удалены в любой момент
Finalizer
Finalizer — проблема для GC и создает дополнительную нагрузку.
Не гарантируется:
* Когда Finalizer будет вызван
* Будет ли Finalizer вообще вызван
* Порядок вызова Finalizer
Примитивы
* Используйте литералы, вместо создания строк
* Используйте глобальную видимость объектов, чтобы их переиспользовать
* Примитивы работают быстрей, чем объектные аналоги
* Условия проверки быстрей, генерации и отлова исключений
* Большое кол-во synchronization блокировок замедляет программу
* Используйте копирование памяти кусками (arraycopy), вместо построчного
Особенности JVM IBM AIX
* типы gc называются по другому, но имеют тот же тип.
Самое близко к G1 — это balanced.
* Активируются расширенные логи GC аналогично:
Но ведутся в формате xml. Визуализировать gc log проще всего тут
Jstat для online просмотра не поддерживается.
* Flight Recorder не поддерживается этой JVM. Для мониторинга работы нужно использовать Healthcenter
Запуск online мониторинга: Накладные расходы при online = 0.4%, при записи в файл = 1%
Просмотр мониторов происходит через Health Center для Eclipse
* Для возможности снятия дампов нужно активировать опцию Xdump:heap После этого дамп можно снять консольной командой: Последующий анализ дампа нужно проводить в MemoryAnalyzer плагине для Eclipse
Передача команд через JCMD не поддерживается.
* Также активировать Heap Dump, Трассировку и VerboseGc можно из Health Center для Eclipse при активированном online мониторинге.