Java-программа с 16 ГБ виртуальной памяти и растущей: это проблема? - PullRequest
5 голосов
/ 05 июня 2011

В Mac OSX 5.8 у меня есть Java-программа, которая работает на 100% CPU очень долгое время - несколько дней или более (это средство проверки моделей, анализирующее параллельную программу, так что это более или менее ожидаемо). Тем не менее, объем виртуальной памяти, как показано в Activity Monitor OSX, становится огромным через день или около того: сейчас он составляет 16 ГБ и продолжает расти. Использование физической памяти примерно стабильно на уровне 1,1 ГБ или около того.

Я хотел бы знать: является ли 16 ГБ (и растет) признаком проблем, которые могут замедлить мою программу?

I start the program with "java -Xmx1024m -ea"

java version "1.6.0_24"
Java(TM) SE Runtime Environment (build 1.6.0_24-b07-334-9M3326)
Java HotSpot(TM) 64-Bit Server VM (build 19.1-b02-334, mixed mode)

Спасибо всем за их предложения. Я попробую предложения по профилированию, приведенные в некоторых ответах, и вернусь (это может занять некоторое время из-за многодневного времени выполнения).

В ответ на некоторые из приведенных ниже моментов средство проверки модели практически не выполняет ввод-вывод (только операторы печати, в зависимости от настроек отладки). В режиме я использую это не имеет GUI. Я не являюсь основным автором средства проверки модели (хотя я работал над некоторыми из его внутренних компонентов), но я не верю, что он использует JNI. [<--- edit: это неправильно, подробности ниже] не делает никакого отображения памяти. Кроме того, я не прошу JVM Oracle / Sun создавать множество потоков (объяснение см. Ниже). </p>

Дополнительная виртуальная память не привела к прекращению работы средства проверки модели, но в зависимости от частоты вывода на печать она постепенно работает все медленнее по мере увеличения использования виртуальной памяти. (Возможно, это только из-за все большего и большего сбора мусора.) Я планирую попробовать его на компьютере с Windows в понедельник, чтобы проверить, не возникает ли такая же проблема.

Небольшое дополнительное объяснение: средство проверки моделей (JPF), которое я запускаю, само по себе является почти полной JVM (полностью написанной на Java), работающей под управлением Oracle / Sun JVM. Конечно, как виртуальная машина, JPF очень специализирован для поддержки проверки моделей.

Это немного нелогично, но это означает, что даже несмотря на то, что программа, которую я проверяю на модели, рассчитана на многопоточность, для JVM от Sun существует только один поток: тот, который выполняет JPF. JPF эмулирует потоки, в которых нуждается моя программа, как часть процесса проверки модели.


Я полагаю, что Стивен С. определил проблему; Роланд Иллиг дал мне инструменты, чтобы проверить это. Я был неправ насчет использования JNI. Сам JPF не использует JNI, но он позволяет подключаемые модули, а JNI использовался одним из настроенных подключаемых модулей. К счастью, есть эквивалентные плагины, которые я могу использовать, которые являются чистой Java. Предварительное использование одного из них не показывает роста виртуальной памяти за последние несколько часов. Спасибо всем за помощь.

Ответы [ 6 ]

11 голосов
/ 05 июня 2011

Я подозреваю, что это тоже утечка. Но это не может быть утечка «нормальной» памяти, потому что опция -Xmx1024m ограничивает нормальную кучу. Аналогично, это не будет утечка кучи «permgen», потому что максимальный размер permgen по умолчанию невелик.

Так что я подозреваю, что это одно из следующего:

  • Вы протекаете темы; то есть потоки создаются, но не завершаются. Они могут быть не активны, но каждый поток имеет сегмент стека (от 256 КБ до 1 МБ по умолчанию ... в зависимости от платформы), который не выделяется в обычной куче.

  • Вы пропускаете файлы с прямым сопоставлением. Они сопоставляются с сегментами памяти, выделенными ОС за пределами обычной кучи. (@bestsss предполагает, что вы ищите утечки дескрипторов ZIP-файлов, что, я думаю, было бы частью этого случая.)

  • Вы используете какой-то код JNI / JNA, из-за которого происходит утечка памяти с помощью malloc, или аналогичный.

В любом случае, профилировщик памяти может изолировать проблему или, по крайней мере, исключить некоторые из возможностей.


Утечка памяти JVM также возможна, но неразумно начинать подозревать JVM, пока вы окончательно не устраните возможные причины в своем собственном коде и библиотеках / приложениях, которые вы используете.

3 голосов
/ 05 июня 2011

Поскольку ваше приложение не является приложением реального времени, вы можете сделать следующее:

jps -v

Получить идентификатор процесса из этой таблицы и сохранить его как pid.

* 1006.*

Файл threads.txt сообщает вам, что процесс делает в данный момент.

Гистограммы использования кучи before-gc.hgr и after-gc.hgr указывают, сколько памяти может освободить полная сборка мусора.

Может быть, из этого вы получите некоторые подсказки о том, что происходит.

0 голосов
/ 05 июня 2011

Вероятно, невозможно ответить на этот вопрос точно, не зная точно, что делает программа. Может быть, он просто использует много памяти ...

В любом случае вы можете попробовать подключиться к процессу с помощью инструмента VisualVM и посмотреть, что происходит с выделением и освобождением памяти.

Кроме того, существует довольно много -XX: опций для отладки сборки мусора, они могут предоставить еще больше информации.

0 голосов
/ 05 июня 2011

Если jvisualvm не сообщает о чрезмерном использовании памяти, это превращается в проблему приложения OS X, где приложением является JVM.

Предлагаю вам открыть такой вопрос.

0 голосов
/ 05 июня 2011

Для меня это звучит как утечка памяти. Вы должны исследовать с помощью профилировщика кучи, такого как VisualVM (который поставляется с вашим JDK).

Редактировать: Я пропустил ваш лимит кучи. Так что это не может быть простой утечкой памяти Java (хотя возможно, по какой-то причине размер кучи игнорируется - все же стоит проверить). Другая возможность состоит в том, что ваше приложение удерживает большое количество ресурсов памяти, не относящихся к куче, таких как собственные узлы графического интерфейса пользователя (окна скрыты, но не удалены), потоки (объекты потоков малы, но имеют большой объем стека, что может никогда не освобождается, если поток, например, создан, но не запущен) или IO (не уверен, как это может занять столько памяти, прежде чем заканчиваются файловые дескрипторы). На более глубоком уровне, как писал Сарнольд, это может быть проблема выделения или утечка памяти внутри самой JVM.

0 голосов
/ 05 июня 2011

Правильно ли вы NULL используете все ссылки после завершения работы с объектами?Интересно, это простая утечка памяти ...

Я видел такое поведение в программах на Си, которые смешивают большое количество выделений и освобождений для объектов разных размеров.Вы можете получить страницы памяти, которые используются не полностью, но у них нет дыр достаточно больших , которые можно было бы использовать для удовлетворения новых запросов памяти.

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

Решением в программах на C обычно является переключение на распределитель slab и хранение объектов разных размеров на разных страницах памяти.Больше нет дырок нечетных размеров, и всегда есть указатель на пробел, подходящий для любого вашего объекта.

Конечно, делать это в управляемой среде, такой как Java, может бытьсложно.Можно было бы надеяться, что JVM уже делает это.(Учитывая, что управляемые среды могут обновлять ссылки на новые области памяти и периодически перепаковывать, даже наивный подход к выделению памяти должен предотвратить глупые дыры.)

Указание на наличие проблемыобычно приходит от трафика подкачки .Если вы видите много трафика подкачки в вашей системе, даже если RSS (Resident Set Size) процесса остается стабильным, то вы могли бы выполнять тонны дискового ввода-вывода для операций, которые выглядят для выполнения полностью в памяти,В Linux и некоторых других системах Unix вы можете найти информацию о трафике подкачки с помощью команды vmstat 1:

$ vmstat 1
procs -----------memory---------- ---swap-- -----io---- -system-- ----cpu----
 r  b   swpd   free   buff  cache   si   so    bi    bo   in   cs us sy id wa
 0  0      0 727392 351128 3846980    0    0    13    16   41   73  3  1 96  0
 0  0      0 727392 351128 3846988    0    0     0     0 1267 4742  5  1 95  0
...

В столбцах si и so показано блоков в секунду .(Хорошо, независимо от того, какой интервал времени вы выбрали с помощью vmstat 1, или vmstat 2, и т. Д.)

Если трафик подкачки низкий, вам, вероятно, не о чем беспокоиться.Если трафик подкачки высок, вам определенно следует попытаться выяснить, почему вы меняете.Это требует больше работы.:)

...