Как анализировать фрагментацию памяти в java?
Мы испытываем несколько минут ожидания на нашем сервере. Вероятно, они запускаются сборками мусора "прекрати мир". Но мы используем параллельную метку и развертку GC (-XX: + UseConcMarkSweepG), поэтому, я думаю, эти паузы вызваны фрагментацией памяти старого поколения.
Как можно проанализировать фрагментацию памяти старого поколения? Есть ли для этого инструменты?
Ломания происходят каждый час. В большинстве случаев они составляют около 20 секунд, но иногда - несколько минут.
Ответы
Ответ 1
Посмотрите на свою документацию по Java для параметров "java -X..." для включения регистрации GC. Это скажет вам, собираете ли вы старое или новое поколение и как долго собираются коллекции.
Пауза "несколько минут" звучит необыкновенно. Вы уверены, что вы не просто работаете с слишком маленьким размером кучи или на машине с недостаточной физической памятью?
-
Если ваша куча слишком близка к полной,
GC будет активирован снова и
снова, в результате ваш сервер
тратя большую часть своего процессорного времени в
GC. Это будет показано в GC
журналы.
-
Если вы используете большую кучу на машине
с недостаточной физической памятью,
полный GC может вызвать
ваша машина "трэш", расходы
большую часть своего времени безумно двигая виртуальными
страниц памяти на диск и обратно. Вы
можно наблюдать это с помощью системы
средства мониторинга; например наблюдая
вывод консоли из "vmstat 5" на
типичная система UNIX/Linux.
Followup
В отличие от веры OP, включение журнала GC вряд ли заметно повлияет на производительность.
Понимание журналов сборочных журналов сбоев Mark Sweep Garbage на сайте Oracle должно быть полезно при интерпретации журналов GC.
Наконец, вывод OP о том, что это проблема "фрагментации", маловероятен, и (IMO) не поддерживается фрагментами доказательств, которые он предоставил. Скорее всего, это что-то еще.
Ответ 2
Для низкоуровневого мониторинга вы захотите использовать этот -XX:PrintFLSStatistics=1
(или сделать его более 2 при большей стоимости блокировки). Он не документирован и иногда дает вам некоторую статистику. К сожалению, это не очень полезно в большинстве приложений по разным причинам, но это, по крайней мере, полезно для шара.
Вы можете увидеть, например,
Max Chunk Size: 215599441
и сравните его с этим
Total Free Space: 219955840
а затем судить о фрагментации на основе средних размеров блоков и количества блоков.
Ответ 3
Я использовал YourKit для хорошего эффекта для этого типа проблем.
Ответ 4
Виталий, Существует проблема фрагментации. Мое наблюдение:
Если есть небольшие размеры объектов, которые часто обновляются, тогда в этом случае создается много мусора. Хотя CMS собирает память, занятую этими объектами, эта память фрагментирована. Теперь Mark-Sweep-Compact поток входит в картинку (останавливает мир) и пытается сжать эту фрагментированную память, вызывая длительную паузу.
Напротив, если размер объектов больше, то он генерирует менее фрагментированную память и
Mark-Swap-Compact занимает меньше времени, чтобы сжать эту память. Это может привести к меньшей пропускной способности, но поможет уменьшить длительную паузу, вызванную уплотнением GC.
Ответ 5
Это сложная проблема. Поскольку я провел некоторое время в системе, чтобы найти это и доказать, позвольте мне перечислить сценарий, где это произошло.
- Мы застряли с использованием Java 6, у которого не было уплотнения сборщика мусора
- В нашем приложении было слишком много GC, в основном, коллекции молодого поколения и большого коллективного коллективного поколения.
- Размер нашей кучи был довольно большой проблемой (мы уменьшили, но наше приложение искажало слишком много строк и коллекций).
Проблема, которая проявилась, заключалась в том, что только один конкретный алгоритм в нашей системе работал медленно; все остальные, которые работали одновременно, работали вполне нормально. Это исключило Full GC; Кроме того, мы использовали jstat и другие j ** инструменты для проверки GC, потоки потоков + хвосты журналов GC.
Из дампов jstack thread, взятых в течение некоторого времени, мы могли получить представление о том, какой блок кода действительно замедлялся. Поэтому сомнение упало до кучи фрагментации.
Чтобы проверить, что я написал простую программу, которая инициализировала два списка List ArrayList и один LinkedList и добавила операции, вызывающие изменение размера. Этот тест я мог бы выполнить с помощью дескриптора REST.
Обычно нет большой разницы. Но внутри фрагментированной кучи есть явная разница в времени; большой размер коллекции с ArrayList становится очень медленным, чем с Linked list. Эти тайминги были зарегистрированы, и для этого не было другого объяснения, кроме фрагментированной главы.
С Java 7 мы перешли на G1GC, а также много работаем в настройке GC и улучшении приложений; Здесь уплотнение кучи намного лучше, и он может обрабатывать большие кучи, хотя я предполагаю, что что-нибудь, что куча более 16 г приземлит вас в местах, где вы действительно не хотите идти, - GC suckage:)
Ответ 6
Чтобы увидеть, как, вероятно, справился с Виталием, см. Общие сведения о журналах коллекционеров мусорных отловов.
Ответ 7
В Java нет фрагментации памяти; во время работы GC, области памяти уплотняются.
Поскольку вы не видите высокую загрузку процессора, также нет GC. Так что что-то еще должно быть причиной ваших проблем. Вот несколько идей:
-
Если база данных вашего приложения находится на другом сервере, могут возникнуть проблемы с сетью.
-
Если вы запустите Windows и у вас установлены сетевые диски, один из дисков может заблокировать ваш компьютер (опять-таки проблемы с сетью). То же самое верно для приводов NFS в Unix. Проверьте системный журнал на наличие сетевых ошибок.
-
Является ли компьютер заменой большого количества данных на диск? Поскольку загрузка процессора низкая, причиной проблемы может быть то, что приложение было заменено на диск, а запуск GC заставил его вернуться в ОЗУ. Это займет много времени, если на вашем сервере недостаточно реальной ОЗУ для хранения всего приложения Java в ОЗУ.
Кроме того, другие процессы могут вывести приложение из ОЗУ. Проверьте реальное использование памяти и использование пространства подкачки.
Чтобы понять вывод журнала GC, этот пост может помочь.
[EDIT] Я до сих пор не могу обойти "низкие CPU" и "GC stalls". Эти два обычно противоречат друг другу. Если GC останавливается, вы должны увидеть 100% использование ЦП. Если CPU неактивен, то что-то еще блокирует GC. У вас есть объекты, которые перегружают finalize()
? Если блокировка завершена, GC может занять все время.