Утечка памяти Java, VisualVM показывает неправильные данные

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

На снимке экрана вы можете видеть диспетчер задач, показывающий использование памяти 700 МБ, и visualvm, показывающий 225...

Кто-нибудь знает, что здесь происходит?

С уважением

введите здесь описание изображения


person vach    schedule 27.01.2014    source источник
comment
если происходит утечка памяти, установите -XX:PermSize=256m -XX:MaxPermSize=256m в качестве аргументов виртуальной машины   -  person lakshman    schedule 27.01.2014
comment
@Vach Это не похоже на утечку памяти ...   -  person assylias    schedule 27.01.2014
comment
@lakshman это вообще не решает утечку памяти PermGenSize, а просто отсрочивает реальную проблему. Лучшим предложением было бы предложить структуру, которая на самом деле способна выгружать классы, если они больше не нужны/не используются. Однако это требует интеллектуальной загрузки классов и, кроме того, довольно строгой обработки (особенно синглтонов и перечислений).   -  person Roman Vottner    schedule 27.01.2014
comment
OFFTOP: Есть ли возможность увеличить изображение?   -  person Tomasz Waszczyk    schedule 27.01.2014
comment
@MrPhi просто щелкните по нему правой кнопкой мыши и откройте изображение в новой вкладке.   -  person vach    schedule 28.01.2014
comment
@assylias Я опишу его поведение, это побочный продукт от vmware под названием gemfire, когда я запускаю его, сначала все работает как надо, но выделение памяти, отображаемое в диспетчере задач, постоянно увеличивается, даже через несколько часов. моя мышь начнет глючить, и я буду вынужден убить процесс... Я использую рабочую станцию ​​Dell Precision, и это не слабая машина...   -  person vach    schedule 28.01.2014
comment
Я хотел бы запустить его, указав параметры java vm, но у меня есть только файл .bat, который запускает саму java-программу и закрывается ... В любом случае, даже если я укажу эти параметры, как сказал @RomanVottner, это не решение, я все еще делаю думаю, что это утечка памяти...   -  person vach    schedule 28.01.2014
comment
@Vach Я вообще не упоминал эти параметры - я просто прокомментировал, что они не решат проблему, а просто отсрочат ее. На мой взгляд, лучший способ обнаружить утечку памяти — это уменьшить заданную память с учетом параметров, представленных lakshman, до минимума, а затем использовать профилировщик для создания дампов памяти, которые затем можно начать анализировать более подробно. Почему вы должны уменьшить память? Так как это заставит GC работать раньше, и ваша проблема, вероятно, возникнет раньше. Более того, heapdumps также не будут занимать много места на диске.   -  person Roman Vottner    schedule 28.01.2014
comment
@Vach Странно, что визуальная виртуальная машина дает неверную информацию. Это может быть проблема с JVM (вы можете попробовать обновиться до последней версии, если это уже не так) или это может быть связано с вашей виртуальной средой (вы можете попробовать запустить приложение на физической машине, чтобы проверить, получаете ли вы такое же поведение).   -  person assylias    schedule 28.01.2014
comment
@RomanVottner спасибо, попробую позже...   -  person vach    schedule 28.01.2014


Ответы (3)


Помните, что ваша ОС знает только об общем объеме памяти, зарезервированном java за это время (и java не будет легко возвращать этот объем памяти, насколько я знаю). Однако java может не использовать всю эту память в данный момент, поэтому вы можете увидеть разницу между этими двумя числами.

Например, если вы запускаете свою программу так

java -Xmx512m -Xms256m ...

Тогда ваша JVM займет 256 МБ, как только она запустится (и ОС сообщит вам об этом более или менее). Однако, если вы откроете инструмент просмотра памяти (будь то visualvm, jconsole и т. д.), он может показать, что вы используете меньше (просто вам не нужно было использовать всю зарезервированную кучу).

person Jorge_B    schedule 27.01.2014
comment
хорошо, это может показать, что я использую меньше, чем это, но если я запускаю данное java-приложение с помощью -Xmx512, означает ли это, что 512 — это максимальная память, определенная для этого приложения, и диспетчер задач теоретически не должен показывать больше выделения, чем 512? или я что-то не понял? - person vach; 28.01.2014
comment
Это будет максимальный размер кучи, но есть и другие регионы, занимающие больше места в операционной системе (часть пространства, которое требуется JVM для размещения собственного кода и переменных в памяти). Возьмите это как ориентацию (но весьма полезно установить ограничения JVM) - person Jorge_B; 28.01.2014

То, что получает Java, не возвращается. Выделение памяти требует довольно много усилий, поэтому Java обычно не возвращает память, когда-либо предоставленную системой. Так что, если ваша программа когда-либо использовала 760 МБ ОЗУ, это то, что она придерживается.

И еще два фактора, которые играют важную роль. Размер кучи — это только объем памяти, который ваша программа использует или может использовать. Но между вашей программой и ОС находится Java-VM, которая также может занимать много памяти. Диспетчер задач показывает объем памяти, который используется вашей программой, плюс виртуальную машину.

Второй фактор — фрагментация памяти. Некоторые структуры данных (например, массивы) должны находиться в последовательном фрагменте памяти. array[i+1] должен находиться в слоте памяти после array[i]. Теперь это означает, что если у вас есть, например. Выделено 10 МБ памяти, а средние 2 МБ используются, и вы хотите создать массив размером 6 МБ, который Java-VM должен выделить для новой памяти, чтобы он мог поместиться в массив одной частью. Это увеличивает использование памяти в диспетчере задач, но не размер кучи, поскольку размер кучи показывает только фактически используемую память.

person Dakkaron    schedule 27.01.2014
comment
на самом деле GC решает проблемы дефрагментации, как вы описали, перемещая память при очистке и освобождении неиспользуемых объектов. - person Roman Vottner; 27.01.2014
comment
Хорошо, имеет смысл. Что ж, вероятно, это произойдет только при запуске GC, что может происходить не одновременно с выделением памяти. Тем более, что нет жесткого стандарта, когда запускается сборщик мусора. - person Dakkaron; 27.01.2014

Пространства памяти в Java определяются тремя показателями: используемое, доступное, максимально доступное (см. значения JMX). Размер, который вы видите, является доступным размером, а не максимально доступным, который, вероятно, уже выделен. Опять же, вы также должны показать некучевую память (обычно меньше, чем куча, но вы должны были настроить ее по-другому). Чтобы быть более точным, вы должны опубликовать свои настройки запуска JVM.

PS: глядя на ваш профиль памяти, я не вижу никакой утечки: я вижу, как JVM сокращает размер кучи, потому что она вообще не используется

person SpyGlassTools.com    schedule 28.01.2014
comment
Ну, если вы посмотрите на Visalvm, вы не увидите никакой утечки, а как насчет диспетчера задач? - person vach; 28.01.2014
comment
В диспетчере задач можно увидеть выделенную память по процессам. Запрос JVM к памяти ОС для своей активности на основе java euristics и настроек jvm, даже если в памяти нет объекта. Запрашивать новую память для ОС дорого, и JVM избегает этого, если это возможно. Опубликуйте свои настройки JVM, чтобы получить окончательное решение вашего вопроса. - person SpyGlassTools.com; 28.01.2014