Аспект дня. Что обычно включает в себя память JVM?

JVM

Обычно мы используем два инструмента: pmap и jcmd.VM.native_memoryКоманда для просмотра использования памяти процессом Java.Поскольку команда pmap немного сложна, а многие карты памяти являются анонимными, здесь мы используем jcmd.VM.native_memoryкоманда, чтобы увидеть каждую часть памяти JVM.

Native Memory Tracking:

Total: reserved=6308603KB, committed=4822083KB
-                 Java Heap (reserved=4194304KB, committed=4194304KB)
                            (mmap: reserved=4194304KB, committed=4194304KB) 
 
-                     Class (reserved=1161041KB, committed=126673KB)
                            (classes #21662)
                            (  instance classes #20542, array classes #1120)
                            (malloc=3921KB #64030) 
                            (mmap: reserved=1157120KB, committed=122752KB) 
                            (  Metadata:   )
                            (    reserved=108544KB, committed=107520KB)
                            (    used=105411KB)
                            (    free=2109KB)
                            (    waste=0KB =0.00%)
                            (  Class space:)
                            (    reserved=1048576KB, committed=15232KB)
                            (    used=13918KB)
                            (    free=1314KB)
                            (    waste=0KB =0.00%)
 
-                    Thread (reserved=355251KB, committed=86023KB)
                            (thread #673)
                            (stack: reserved=353372KB, committed=84144KB)
                            (malloc=1090KB #4039) 
                            (arena=789KB #1344)
 
-                      Code (reserved=252395KB, committed=69471KB)
                            (malloc=4707KB #17917) 
                            (mmap: reserved=247688KB, committed=64764KB) 
 
-                        GC (reserved=199635KB, committed=199635KB)
                            (malloc=11079KB #29639) 
                            (mmap: reserved=188556KB, committed=188556KB) 
 
-                  Compiler (reserved=2605KB, committed=2605KB)
                            (malloc=2474KB #2357) 
                            (arena=131KB #5)
 
-                  Internal (reserved=3643KB, committed=3643KB)
                            (malloc=3611KB #8683) 
                            (mmap: reserved=32KB, committed=32KB) 
 
-                     Other (reserved=67891KB, committed=67891KB)
                            (malloc=67891KB #2859) 
 
-                    Symbol (reserved=26220KB, committed=26220KB)
                            (malloc=22664KB #292684) 
                            (arena=3556KB #1)
 
-    Native Memory Tracking (reserved=7616KB, committed=7616KB)
                            (malloc=585KB #8238) 
                            (tracking overhead=7031KB)
 
-               Arena Chunk (reserved=10911KB, committed=10911KB)
                            (malloc=10911KB) 
 
-                   Tracing (reserved=25937KB, committed=25937KB)
                            (malloc=25937KB #8666) 
 
-                   Logging (reserved=5KB, committed=5KB)
                            (malloc=5KB #196) 
 
-                 Arguments (reserved=18KB, committed=18KB)
                            (malloc=18KB #486) 
 
-                    Module (reserved=532KB, committed=532KB)
                            (malloc=532KB #3579) 
 
-              Synchronizer (reserved=591KB, committed=591KB)
                            (malloc=591KB #4777) 
 
-                 Safepoint (reserved=8KB, committed=8KB)
                            (mmap: reserved=8KB, committed=8KB) 

здесьmmap,mallocНапример, есть два разных метода выделения памяти:

Internal (reserved=3643KB, committed=3643KB)
                            (malloc=3611KB #8683) 
                            (mmap: reserved=32KB, committed=32KB) 

представлятьInternalзанято всего3643KB3611KBчерез метод malloc,32KBЕсть через mmap путь. Арена — это память, выделенная malloc, но она не освобождается после выполнения кода, она будет продолжать использоваться после того, как будет помещена в чанк арены.MallocInternals

Видно, что память процесса Java включает в себя:

  • Java Heap: куча памяти, т.е.-XmxОграничьте максимальный размер кучи памяти.
  • Class: Загруженная информация о классе и методе на самом деле представляет собой метапространство, состоящее из двух частей: одна — это метаданные,-XX:MaxMetaspaceSizeОграничение максимального размера, в дополнение к пространству класса, составляет-XX:CompressedClassSpaceSizeограничить максимальный размер
  • Thread: Потоки и стеки потоков занимают память, и на размер каждого стека потоков влияет-XssОграничение есть, но нет ограничения на общий размер.
  • Code: Код после JIT-компиляции точно в срок (оптимизированный компилятором C1 C2) занимает память и подлежит-XX:ReservedCodeCacheSizeограничение
  • GC: Сборка мусора занимает память, например, CardTable, необходимая для сборки мусора, количество меток, запись разделения области, метка GC Root и т. д., все из которых требуют памяти. Это не ограничено и, как правило, не очень велико.
  • Compiler: Память, занимаемая кодом и тегами самого компилятора C1 C2, не ограничена и в целом не очень велика.
  • Internal: Разбор командной строки, память, используемая JVMTI, это не ограничено и, как правило, не очень большое
  • Symbol: размер, занимаемый пулом констант, пул строковых констант подлежит-XX:StringTableSizeКоличество ограничено, а общий объем памяти не ограничен
  • Native Memory Tracking:Размер памяти, занимаемый самим набором памяти.Если набор не включен (тогда этого не видно, ха-ха), он не будет занят.Это не ограничено и в целом не очень большое.
  • Arena Chunk: Вся память, выделенная ареной, не ограничена, как правило, не очень большая
  • Tracing: Память, занятая всеми сборами данных, если JFR включена, это в основном память, занятая JFR. Это не ограничено, как правило, не очень большое
  • Логирование, Аргументы, Модуль, Синхронизатор, Сейфпойнт, Другое — обычно нас это не волнует.

В дополнение к использованию памяти, регистрируемому Native Memory Tracking, существует два типа памяти.Отслеживание собственной памяти не регистрируется,Это:

  • Direct Buffer: Прямая память, в основном относится кjava.nio.DirectByteBufferВыделяет память во время создания. Зачем использовать память вне кучи? Обычно потому что:

    • Может использоваться совместно между процессами, что снижает репликацию между виртуальными машинами.
    • Улучшения приостановки сборки мусора: если некоторые долгоживущие объекты, существующие в большом количестве приложений, часто вызывают YGC или FullGC, вы можете рассмотреть возможность удаления этих объектов из кучи. Чрезмерно большая куча может повлиять на производительность приложений Java. Если используется память вне кучи, памятью вне кучи управляет непосредственно операционная система (а не виртуальная машина). Результатом этого является сохранение небольшого объема памяти в куче, чтобы уменьшить влияние сборки мусора на приложение.
    • В некоторых сценариях производительность программных операций ввода-вывода может быть улучшена. Этап копирования данных из памяти в куче в память вне кучи исключен.
  • MMap Buffer: Память с отображением файлов, хотя Java Memory Mapped Files присутствует в пакете java.nio начиная с JDK 1.4, для многих разработчиков программ это все еще довольно новая концепция. После появления NIO Java IO уже работает достаточно быстро, а файлы с отображением памяти обеспечивают самые быстрые операции ввода-вывода, возможные в Java, поэтому эти высокопроизводительные Java-приложения должны использовать файлы с отображением памяти для сохранения данных. В качестве важной функции NIO метод Mmap предоставляет нам возможность отобразить часть или весь файл в адресное пространство памяти, при этом, когда эта область памяти будет записана в грязную страницу, операционная система будет использовать некоторое количество Алгоритм записывает эти данные в файл, и нашей java-программе не нужно об этом заботиться. Это ключевое преимущество отображаемых в память файлов: даже если ваша программа зависнет сразу после записи в память, операционная система все равно запишет данные из памяти в файловую систему. Другим более заметным преимуществом является общая память.К файлам, отображаемым в память, могут обращаться несколько процессов одновременно, выступая в качестве общей памяти с малой задержкой.