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

Как процесс JVM распределяет свою память?

У меня есть небольшой пробел в понимании того, как JVM-процесс распределяет свою собственную память. Насколько я знаю

RSS = Heap size + MetaSpace + OffHeap size

где OffHeap состоит из стеков потоков, прямых буферов, отображенных файлов (библиотек и банок) и самого кода JVM;

В настоящий момент Im пытается проанализировать мое приложение Java (Spring Boot + Infinispan), который RSS 779M (он работает в контейнере докера, поэтому pid 1 в порядке):

[ [email protected]:/data ]$ ps -o rss,vsz,sz 1
RSS    VSZ    SZ
798324 6242160 1560540

Согласно jvisualvm, зафиксированный размер кучи 374M введите описание изображения здесь

Размер Metasapce 89M
введите описание изображения здесь

Другими словами, я хочу объяснить 799M - (374M + 89M) = 316M памяти OffHeap.

Мое приложение имеет (в среднем) 36 живых потоков. введите описание изображения здесь

Каждый из этих потоков потребляет 1M:

[ [email protected]:/data ]$ java -XX:+PrintFlagsFinal -version |grep ThreadStackSize    
intx CompilerThreadStackSize                   = 0
intx ThreadStackSize                           = 1024
intx VMThreadStackSize                         = 1024

Итак, здесь мы можем добавить 36M.

Единственное место, где приложение использует DirectBuffer, это NIO. Насколько я могу видеть из JMX, он не потребляет много ресурсов - только 98K введите описание изображения здесь

Последний шаг - это сопоставленные libs и jars. Но согласно pmap (полный вывод)

[ [email protected]:/data ]$ pmap -x 1 | grep ".so.*" | awk '{ sum+=$3} END {print sum}'

12896K

плюс

[email protected]:/data ]$ pmap -x 1 | grep ".jar" | awk '{ sum+=$3} END {print sum}'

9720K

мы имеем только 20M.

Следовательно, нам еще нужно объяснить 316M - (36M + 20M) = 260M: (

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

4b9b3361

Ответ 1

Подход:

Возможно, вы захотите использовать Java HotSpot Native Memory Tracking (NMT).

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

Использование

  • Вы можете запустить приложение с помощью -XX:NativeMemoryTracking=summary.

  • Наблюдения текущей кучи можно выполнить с помощью jcmd <pid> VM.native_memory summary.

Где найти jcmd/pid:

При установке OpedJDK по умолчанию на Ubuntu это можно найти в /usr/bin/jcmd.

Просто запустив jcmd без каких-либо параметров, вы получите список запущенных приложений Java.

[email protected]:~$ /usr/bin/jcmd
5169 Main                       <-- 5169 is the pid

Выход

Затем вы получите полный обзор своей кучи, выглядя примерно так:

Всего: зарезервировано = 664192KB, зафиксировано = 253120KB < --- общая память, отслеживаемая отслеживанием основной памяти

  • Java Heap (зарезервировано = 516096 КБ, зафиксировано = 204800 КБ) < --- Java Heap

    (mmap: reserved = 516096KB, commit = 204800KB)

  • Класс (зарезервировано = 6568 КБ, зафиксировано = 4140 КБ) < --- метаданные класса

    (классы # 665) < --- количество загруженных классов

    (malloc = 424KB, # 1000) < --- malloc'd memory, #number of malloc

    (mmap: зарезервировано = 6144 КБ, зафиксировано = 3716 КБ)

  • Тема (зарезервировано = 6868 КБ, зафиксировано = 6868 КБ)                         (поток # 15) < --- количество потоков

    (stack: reserved = 6780KB, commit = 6780KB) < --- память, используемая стеками потоков

    (malloc = 27KB, # 66)

    (arena = 61KB, # 30) < --- ресурсы и области обработки

  • Код (зарезервировано = 102414 КБ, зафиксировано = 6314 КБ)

    (malloc = 2574KB, # 74316)

    (mmap: зарезервировано = 99840 КБ, зафиксировано = 3740 КБ)

  • GC (зарезервировано = 26154 КБ, зафиксировано = 24938 КБ)

    (malloc = 486KB, # 110)

    (mmap: reserved = 25668KB, commit = 24452KB)

  • Компилятор (зарезервировано = 106 КБ, зафиксировано = 106 КБ)

    (malloc = 7KB, # 90)

    (arena = 99KB, # 3)

  • Внутренний (зарезервировано = 586 КБ, зафиксировано = 554 КБ)

    (malloc = 554KB, # 1677)

    (mmap: reserved = 32KB, commit = 0KB)

  • Символ (зарезервировано = 906 КБ, зафиксировано = 906 КБ)

    (malloc = 514KB, # 2736)

    (arena = 392KB, # 1)

  • Отслеживание памяти (зарезервировано = 3184 КБ, зафиксировано = 3184 КБ)

    (malloc = 3184KB, # 300)

  • Объединенные свободные куски (зарезервировано = 1276 КБ, зафиксировано = 1276 КБ)

    (таНос = 1276KB)

  • Неизвестно (зарезервировано = 33 КБ, зафиксировано = 33 КБ)

    (arena = 33KB, # 1)

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

Я не знаю метода, который дает вам более подробный список потребления памяти.

Дальнейшее чтение:

Вы также можете использовать -XX:NativeMemoryTracking=detail в сочетании с дополнительными командами jcmd. Более подробное объяснение можно найти в Java Platform, Standard Edition Руководство по устранению неполадок - 2.6 Утилита jcmd. Вы можете проверить возможные команды с помощью "jcmd <pid> help"