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



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



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


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





консультант сказал нам, что вызов gc() явно неверен: "пусть jvm решает, когда запускать gc". В основном его аргументы были те же, что и здесь.
Но я все равно не понимаю:




  • как я могу иметь кривую использования памяти?

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

938   14  

14 ответов:

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

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

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

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

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

в теории, теории и практике то же самое. На практике это не так.

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

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

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

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

пример: JVM Memory Dashboard

посмотри сайт проекта для просмотра скриншотов, описания функций и документации.

примечание: Я разработчик stagemonitor

заглянуть в то, что происходит внутри tomcat через Visual VM. http://www.skill-guru.com/blog/2010/10/05/increasing-permgen-size-in-your-server/ alt text

alt text

взгляните на JVM args: 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 с read anything and everything the Брайан Гетц пишет.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

ссылка

Comments

    Ничего не найдено.