Подтвердить что ты не робот

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

У нас есть приложение 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". В основном его аргументы были такими же, как здесь обсуждались. Но я до сих пор не понимаю:

  • Как я могу использовать кривую использования памяти?
  • Что не так с явным gc()? Меня не волнуют небольшие проблемы с производительностью, которые могут возникнуть с явным gc() и которые я буду оценивать в 1-3%. Мне нужен монитор памяти и потока, который помогает мне в анализе нашей системы на сайте клиента.
4b9b3361

Ответ 1

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

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

Ответ 2

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

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

Ответ 3

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

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

Пример: JVM Memory Dashboard

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

Примечание. Я разработчик stagemonitor

Ответ 4

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

В теории теория и практика одинаковы. На практике это не так.

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

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

Ответ 7

Взгляните на аргументы JVM: http://java.sun.com/javase/technologies/hotspot/vmoptions.jsp#DebuggingOptions

XX: -PrintGC Печать сообщений в сборке мусора. Управляемость.

-XX: -PrintGCDetails Распечатайте более подробную информацию в сборке мусора. Управляемость. (Представлено в 1.4.0.)

-XX: -PrintGCTimeStamps Печать временных меток при сборке мусора. Управляемый (введен в 1.4.0.)

-XX: -PrintTenuringDistribution Печатать информацию о возрасте хранения.

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

Ответ 8

Явная работа SystemGc() в производственной системе - ужасная идея. Если память доходит до любого размера, вся система может замерзнуть, пока работает полный GC. На сервере с несколькими гигабайтами это может быть очень заметно, в зависимости от того, как настроен jvm, и сколько у него запаса, и т.д. - я видел паузы более 30 секунд.

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

Как отмечает Nick Holt post, опции для печати GC-активности уже существуют как флаги JVM.

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

Ответ 9

Если вам нравится хороший способ сделать это из командной строки, используйте jstat:

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

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

Ответ 10

Если вы используете java 1.5, вы можете посмотреть на ManagementFactory.getMemoryMXBean(), который даст вам числа на все виды памяти. куча и не куча, perm-gen.

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

Ответ 11

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

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

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

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

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

Ответ 12

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

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

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

Ответ 13

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

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

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

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

Ответ 14

Добавление в список ответов JConsole (входит в каталог jdk/bin) - также хороший интерфейс для тестирования.

Ссылка