2016-09-25 3 views
2

У меня есть Java-приложение, работающее на Java 8 внутри контейнера докеров. Процесс запускает сервер Jetty 9 и развертывается веб-приложение. Следующие опции JVM передаются: -Xms768m -Xmx768m.Использование памяти процесса Java (jcmd vs pmap)

Недавно я заметил, что процесс потребляет много памяти:

$ ps aux 1 
USER  PID %CPU %MEM VSZ RSS TTY  STAT START TIME COMMAND 
app   1 0.1 48.9 5268992 2989492 ?  Ssl Sep23 4:47 java -server ... 

$ pmap -x 1 
Address   Kbytes  RSS Dirty Mode Mapping 
... 
total kB   5280504 2994384 2980776 

$ jcmd 1 VM.native_memory summary 
1: 

Native Memory Tracking: 

Total: reserved=1378791KB, committed=1049931KB 
-     Java Heap (reserved=786432KB, committed=786432KB) 
          (mmap: reserved=786432KB, committed=786432KB) 

-      Class (reserved=220113KB, committed=101073KB) 
          (classes #17246) 
          (malloc=7121KB #25927) 
          (mmap: reserved=212992KB, committed=93952KB) 

-     Thread (reserved=47684KB, committed=47684KB) 
          (thread #47) 
          (stack: reserved=47288KB, committed=47288KB) 
          (malloc=150KB #236) 
          (arena=246KB #92) 

-      Code (reserved=257980KB, committed=48160KB) 
          (malloc=8380KB #11150) 
          (mmap: reserved=249600KB, committed=39780KB) 

-      GC (reserved=34513KB, committed=34513KB) 
          (malloc=5777KB #280) 
          (mmap: reserved=28736KB, committed=28736KB) 

-     Compiler (reserved=276KB, committed=276KB) 
          (malloc=146KB #398) 
          (arena=131KB #3) 

-     Internal (reserved=8247KB, committed=8247KB) 
          (malloc=8215KB #20172) 
          (mmap: reserved=32KB, committed=32KB) 

-     Symbol (reserved=19338KB, committed=19338KB) 
          (malloc=16805KB #184025) 
          (arena=2533KB #1) 

- Native Memory Tracking (reserved=4019KB, committed=4019KB) 
          (malloc=186KB #2933) 
          (tracking overhead=3833KB) 

-    Arena Chunk (reserved=187KB, committed=187KB) 
          (malloc=187KB) 

Как вы можете видеть, что есть огромная разница между RSS (2,8GB) и то, что на самом деле показывается носителем памяти В.М. статистика (1,0 ГБ, 1,3 ГБ).

Почему существует такая огромная разница? Я понимаю, что RSS также показывает распределение памяти для разделяемых библиотек, но после анализа подробного вывода pmap я понял, что это не проблема разделяемых библиотек, а память потребляется кем-то, что называется структурой [anon]. Почему JVM выделяет столько анонимных блоков памяти?

Я искал и нашел следующую тему: Why does a JVM report more committed memory than the linux process resident set size? Однако случай, описанный здесь отличается, потому что меньше использование памяти показывается RSS, чем статистика виртуальной машины Java. Я имею противоположную ситуацию и не могу понять причину.

+0

У меня такая же проблема, у меня есть java-процесс с Xmx 1.5g (Oracle Jvm), который потребляет около 3,1 г, когда я вижу в команде TOP, однако такое же приложение, когда я запускаю openjdk, он потребляет около 2,3 ГБ выше выделенного xmx), я до сих пор не нашел ответа на это. Дайте мне знать, если вы найдете решение. Спасибо –

ответ

1

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

+0

Можете ли вы порекомендовать какой-либо простой способ взглянуть на это? Я быстро просмотрел дамп памяти процесса, но не нашел ничего подозрительного. – Konrad

+0

visualvm может контролировать использование DBB. https://blogs.oracle.com/alanb/entry/monitoring_direct_buffers – the8472

+0

Я не вижу существенного использования NIO-сопоставленных/прямых байтовых буферов. Здесь вы можете увидеть использование свободной памяти буферов: [direct] (http://s16.postimg.org/zcdhmk00l/nio_buffers.png). Для отображаемых буферов он показывает 0. – Konrad

0

После глубокого анализа в соответствии со следующей статьей: https://gdstechnology.blog.gov.uk/2015/12/11/using-jemalloc-to-get-to-the-bottom-of-a-memory-leak/ мы выяснили, что проблема связана с распределением памяти по java.util.zip.Inflater.

Еще нужно выяснить, какие вызовы java.util.zip.Inflater.inflateBytes и искать возможные решения.

+0

Вы можете использовать https://github.com/devexperts/aprof для этой задачи. – egorlitvinenko

1

Я столкнулся с аналогичной проблемой с одной из наших задач Apache Spark, где мы отправляли наше приложение в виде толстой банки. После анализа дампов потоков мы поняли, что Hibernate является виновником, мы использовали для загрузки классов спящего режима при запуске приложения который на самом деле использовал java.util.zip.Inflater.inflateBytes для чтения файлов класса спящего режима, это превысило использование нашего родного резидентного памяти почти на 1,5 Гб, вот ошибка, поднятая в спящем режиме для этой проблемы. https://hibernate.atlassian.net/browse/HHH-10938?attachmentOrder=desc, исправление, предложенное в комментариях для нас, Надеюсь, это поможет ,

+0

Мы используем Jetty и развертываем «жирную» WAR с включенными всеми зависимостями. Если мы разворачиваем «тонкий» JAR и копируем все зависимости в Jetty libs, он решает проблему. Похоже, что большинство серверов веб-приложений имеют схожие проблемы. – Konrad

+0

@ Konrad Не могли бы вы объяснить, что вы имеете в виду под тонкой банкой и скопировать все зависимости. Я использую причал и испытываю высокое использование памяти без кучи. – cppcoder

+0

По тонкому JAR я имею в виду, что он содержит только: - скомпилировал классы - ресурсы Другие зависимости (все другие файлы JAR) копируются в каталог jetty lib. В этом случае, когда Jetty запускает приложение, ему не нужно искать зависимости внутри приложения JAR/WAR и не нужно извлекать его в какой-либо временный каталог. Он просто идет в его собственный каталог lib, и там есть зависимости. – Konrad