Вопрос по java – Как контролировать использование памяти Java?

54

У нас есть приложение j2ee, работающее на Jboss, и мы хотим отслеживать использование его памяти. В настоящее время мы используем следующий код

    System.gc();
    Runtime rt = Runtime.getRuntime();
    long usedMB = (rt.totalMemory() - rt.freeMemory()) / 1024 / 1024;
    logger.information(this, "memory usage" + usedMB);

Этот код работает нормально. Это означает, что он показывает кривую памяти, которая соответствует действительности. Когда мы создаем большой файл XML из БД, кривая идет вверх, а после завершения извлечения она идет вниз.

alt text

Консультант сказал нам, что явно вызывать gc () неправильно, «пусть jvm решает, когда запускать gc». В основном его аргументы были такими же, какобсуждать здесь. But I still don't understand:

how can I have my memory usage curve? what is wrong with the explicit gc()? I don't care about small performance issues which can happen with explicit gc() and which I would estimate in 1-3%. What I need is memory and thread monitor which helps me in analysis of our system on customer site.
монитор с jvisualvm - дает лучшую статистику. Thorbjørn Ravn Andersen

Ваш Ответ

13   ответов
4

используйте jstat:

http://java.sun.com/j2se/1.5.0/docs/tooldocs/share/jstat.html

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

48

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

Ничто не является действительно "неправильным" с явными вызовами gc (). Однако помните, что когда вы вызываете gc (), вы предлагаете & quot; что сборщик мусора работает. Нет никаких гарантий, что он будет запущен в то время, когда вы запускаете эту команду.

Я использовал визуальную виртуальную машину, и она работает потрясающе. Он показывает так много деталей внутри сервера.
Просто смотрю на VisualVM - это мило.
System.gc () может повредить производительности, потому что она мешает алгоритмам GC. Это может ухудшить все последующие GC.
[цитата нужна] Хотите продемонстрировать свою претензию? Пожалуйста, объясните, как выполнение вызова gc () "мешает" & quot; с алгоритмами сборщиков мусора и тем, как вызов метода «ухудшается»; последующие звонки?
Есть причина, по которой виртуальная машина имеет параметр -XX: + DisableExplicitGC! Проблема не в том, что обязательно нужно звонить в GC. Но это может быть плохо, если вы позвоните в GCtoo often, Это может вызвать полный GC, когда большинство алгоритмов не останавливают всю виртуальную машину для полного GC. Это может быть особенно проблематичным, если вы запускаете ОГРОМНОЕ, когда вся ВМ может остановиться на несколько минут. Если это произойдет, вы можете настроить тайм-аут других операций (например, соединения с базой данных, соединения rmi и т. Д.).
2

вы можете использовать то же самое до / после чисел, вам просто не нужно форсировать GC.

Вам просто нужно помнить, что эти запуски GC (обычно один для старого и один для нового поколения) не находятся на регулярных интервалах, поэтому вам нужно извлечь начальное время, а также для построения графика (или вы используете график для порядкового номера, для большинства практические цели, которых было бы достаточно для заговора).

Например, на виртуальной машине Oracle HotSpot с ParNewGC существует JMX MBean, называемыйjava.lang:type=GarbageCollector,name=PS Scavenge, он имеет атрибут LastGCInfo, он возвращает CompositeData последнего запуска YG-мусорщика. Записано сdurationабсолютstartTime а такжеmemoryUsageBefore а такжеmemoryUsageAfter.

Просто используйте таймер, чтобы прочитать этот атрибут. Всякий раз, когда появляется новый startTime, вы знаете, что он описывает новое событие GC, вы извлекаете информацию о памяти и продолжаете опрос для следующего обновления. (Не уверен, еслиAttributeChangeNotification как-то можно использовать.)

Совет: в своем таймере вы можете измерить расстояние до последнего прогона ГХ, и если оно слишком велико для возобновления печати, вы можете условно вызвать System.gc (). Но я бы не стал этого делать в экземпляре OLTP.

28

которые позволяют контролировать использование памяти виртуальной машиной.ВМ может выставлять статистику памяти, используя JMX, Вы также можетераспечатать статистику GC чтобы увидеть, как память работает со временем.

Вызов System.gc () может повредить производительности GC, поскольку объекты будут преждевременно перемещены из нового в старое поколения, а слабые ссылки будут преждевременно удалены. Это может привести к снижению эффективности памяти, увеличению времени GC и уменьшению обращений к кешу (для кешей, использующих слабые ссылки). Я согласен с вашим консультантом: System.gc () - это плохо. Я бы дошел доотключи это используя переключатель командной строки.

+1 за отличный комментарий о преждевременном продвижении.
5

я. Если объем памяти достигнет какого-либо размера, вся система может зависнуть, пока работает полный сборщик мусора. На сервере размером в несколько гигабайт это может быть очень заметно, в зависимости от того, как настроен jvm, и сколько у него запаса, и т. Д. И т. Д. - я видел паузы длительностью более 30 секунд.

Другая проблема состоит в том, что, явно вызывая GC, вы фактически не отслеживаете, как JVM выполняет GC, вы фактически изменяете его - в зависимости от того, как вы настроили JVM, он собирается собирать мусор, когда это необходимо, и обычно постепенно (он просто не запускает полный сборщик мусора, когда ему не хватает памяти). То, что вы будете распечатывать, будет совсем не похоже на то, что будет делать JVM самостоятельно - во-первых, вы, вероятно, увидите меньше автоматических / инкрементальных GC, поскольку вы будете очищать память вручную.

Как отмечается в сообщении Ника Холта, варианты печати активности GC уже существуют как флаги JVM.

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

Как это можно избежать, не вызывая System.gc ()? В конце концов, мусор JVM собирается, когда ему не хватает памяти, поэтому задержка не произойдет? (Это был мой опыт по крайней мере).
JVM позволяет вам определять из нескольких алгоритмов GC. Все они выполняют своего рода инкрементальный сборщик мусора и могут иногда запускать полный сборщик мусора (я не слишком подробно разбираюсь в деталях, но в основном только тогда, когда им приходится - что-то вроде «последней инстанции», например, когда это происходит). ; недостаточно места, чтобы сделать новую копию некоторого раздела mem во время инкрементного gc). Если вы регулярно звоните System.gc, это будет происходить гораздо чаще. Вы, по сути, создаете свою собственную стратегию GC, которая "просто периодически запускает полный GC". У JVM есть лучшие стратегии, чем эта.
5

http://java.sun.com/javase/technologies/hotspot/vmoptions.jsp#DebuggingOptions

XX:-PrintGC Print messages at garbage collection. Manageable.

-XX:-PrintGCDetails Print more details at garbage collection. Manageable. (Introduced in 1.4.0.)

-XX:-PrintGCTimeStamps Print timestamps at garbage collection. Manageable (Introduced in 1.4.0.)

-XX:-PrintTenuringDistribution Print tenuring age information.

Пока вы не собираетесь расстраивать JVM явными вызовамиSystem.gc() они могут не иметь ожидаемого эффекта. Чтобы действительно понять, что происходит с памятью в JVM с чтением чего-либо и всего,Брайан Гетц пишет.

9

stagemonitor, Это монитор производительности Java-приложений с открытым исходным кодом. Он фиксирует метрики времени ответа, метрики JVM, детали запроса (включая стек вызовов, захваченный профилировщиком запросов) и многое другое. Накладные расходы очень низкие.

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

Пример: JVM Memory Dashboard

Посмотрите навеб-сайт проекта чтобы увидеть скриншоты, описания функций и документацию.

Примечание: я разработчик stagemonitor

спасибо, я посмотрю на это. Oleg Pavliv
0

попробуйте VisualVM, чтобы получить базовый вид.

Вы также можете использовать Eclipse MAT, чтобы сделать более подробный анализ памяти.

Для правильности вашей программы вполне допустимо использовать System.gc (), если вы не зависите от него.

9

что консультант прав в теории, а вы правы на практике. Какпоговорка идет:

In theory, theory and practice are the same. In practice, they are not.

В спецификации Java сказано, что System.gc предлагает вызывать сборщик мусора. На практике это просто порождает поток и сразу запускается на Sun JVM.

Хотя теоретически вы можете испортить какую-то тонко настроенную реализацию сборки мусора в JVM, если вы не пишете универсальный код, предназначенный для развертывания на какой-либо JVM, не беспокойтесь об этом. Если это работает для вас, сделайте это.

Вы знаете, если это поведениеjust spawns a thread and runs right away также применимо к текущей (Sun / Oracle / Hotspot) JVM (8)?
Запуск System.gc часто, просто чтобы получить разумную статистику использования памяти,will повредить производительность. Так что это не просто сделай это. System.gc () имеет смысл в случаях, подобных & quot; ОК, теперь большая работа, которая требовала большой памяти, сделана, и мне сейчас особо нечего делать, поэтому я собираю мусор, чтобы повысить производительность небольших сборок мусора позже. & Quot;
2

вы можете посмотреть на ManagementFactory.getMemoryMXBean (), который дает вам цифры на все виды памяти. куча и не куча, Пермь-генерал.

Хороший пример можно найти там http://www.freshblurbs.com/explaining-java-lang-outofmemoryerror-permgen-space

0

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

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

Лучшая практика будетprobably использовать его только там, где вы можете выполнять большое количество освобождения (например, сбрасывать большой массив).

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

Похожие вопросы