jvm: модель памяти, выделение памяти и механизм сборки мусора

JVM

1. Зачем изучать JVM?

  • Я впервые столкнулся с JVM, потому что в последнее время меня часто спрашивали об интервью, поэтому я прочитал «Углубленное понимание виртуальной машины Java: расширенные функции и лучшие практики JVM», очень хорошую книгу и рекомендуется.
  • Прочитав несколько глав, у меня появилось определенное понимание всего процесса выполнения куска кода на Java, например, ознакомившись с моделью памяти, я обнаружил, что stackoverflow (переполнение стека) и OutofMemory (нехватка памяти) в основном вызваны по этим типам ошибок.В чем причина? Какие есть решения для разных типов?
  • Основная цель написания этого блога — соединить все точки знаний о jvm, которые я видел в последнее время, чтобы я мог лучше понять это позже.
  • что такое двм: Виртуальный компьютер является частью JRE. Цель использования JVM является поддержка кроссплатформы независимо от операционной системы. Внутренняя архитектура JVM в основном разделена на три части:Подсистема загрузчика классов, область данных времени выполнения и механизм выполнения.

  • Разница между кроссплатформенностью в java и кроссплатформенностью C++: Смысл кроссплатформенности в java заключается в кроссплатформенности jvm (рабочий диапазон), а кроссплатформенность c++ в кроссплатформенности jdk (во время компиляции);

2. Основное содержание:

2.1 выполнение java-кода

1. исходный файл java - "компилятор -" файл байт-кода;
2. файлы байт-кода - машинный код "jvm-" (см. выше)

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

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

2.2 область памяти Java

1. Область рабочих данных

  • Жизненный цикл частной области данных потока такой же, как и у потока, каждый поток напрямую сопоставляется с локальным потоком операционной системы, и эта часть области памяти создается и уничтожается локальным потоком.
  • Область совместного использования потоков создается при запуске виртуальной машины и уничтожается при ее выключении.
  • Помимо ПК, другие области могут вызывать OOM.

2. Прямая память

  • Часто используется прямая память, что может привести к OOM
  • Метод ввода-вывода, основанный на CHANEL и буфере, представлен в NIO, а память вне кучи может быть напрямую выделена с помощью собственной библиотеки функций. Используйте объект DirectByteBuffer в качестве ссылки на эту память. Это позволяет избежать копирования данных туда и обратно между кучей Java и собственной кучей, поэтому в некоторых сценариях производительность может быть значительно улучшена.

3. Основное содержимое области рабочих данных

  • pc: указывает на номер строки байт-кода, выполняемого текущим потоком.
  • стек виртуальных машин: В основном описывают выполнение метода.Каждый метод создает кадр стека во время выполнения, в котором кадр стека хранит такую ​​информацию, как таблица локальных переменных, стек операндов, динамическая ссылка, выход из метода и т. д. От вызова до конца выполнения каждый метод соответствует процессу помещения кадра стека в стек в стеке виртуальной машины.
  • область локального метода: стек виртуальной машины выполняет метод java, локальный стек методов выполняет собственный метод. Например, здесь выполняется вызов метода на C или C++ в java. Некоторые виртуальные машины объединяют стек виртуальных машин со стеком собственных методов.

  • куча: созданные объекты и массивы хранятся в памяти кучи java.Поскольку они совместно используются потоками, они представляют собой области сбора мусора с областью методов.С точки зрения GC, куча java подразделяется на: новую область и старую площадь.
  • область метода: Используется для хранения данных, таких как информация о классе, константы, статические переменные и код, скомпилированный компилятором реального времени, загруженным jvm. **Использование постоянной генерации кучи java для реализации области метода, области постоянной генерации, собранной сборщиком мусора. **Основной целью восстановления памяти постоянного поколения является перезапуск пула констант и выгрузка типа. Пул констант времени выполнения является частью области методов.Помимо информации описания версии класса, поля, метода, интерфейса и т. д., файл класса также имеет пул констант, в котором в основном хранятся различные литералы и символические ссылки, сгенерированные во время компиляция.Часть содержимого сохраняется в пуле констант времени выполнения области методов после загрузки класса.

2.3 Как JVM выделяет память?

1. Распределение кучи

Хранить экземпляры объектов и массивы

2. Размещение в стеке

хранить локальные переменные

Пространство памяти стека Java используется для выполнения потоков. Память стека всегда следует порядку LIFO (последним поступил – первым обслужен). Всякий раз, когда выполняется метод, в памяти стека создается новый кадр стека для сохранения определения в функция Базовые переменные типа данных и ссылочные переменные объектов;
Когда метод завершается, кадр стека меняет свое состояние на неиспользуемое и может использоваться для выполнения следующего метода.

Пример понимания Stacks Inn:
Код:


public class HeapStackTestMemory {

    public static void main(String[] args) { //Line 1

        int i = 1; //Line 2

        Object obj = new Object(); //Line 3

        HeapStackTestMemory mem = new HeapStackTestMemory(); //Line 4

        mem.foo(obj);  //Line 5

    }  //Line 9

    private void foo(Object param) {  //Line 6

        String str = param.toString();  //Line 7

        System.out.println(str);

    } //Line 8

}

Этапы выполнения программы:

  • Как только мы запустим программу, она загрузит все классы среды выполнения в пространство кучи памяти, найдет метод main() в строке 1, среда выполнения Java создаст пространство стека, используемое потоком метода main().
  • Во второй строке мы создаем локальную переменную примитивного типа данных, поэтому она будет храниться в пространстве стека памяти метода main().
  • В строке 3 мы создаем объект типа Object, поэтому он создается в пространстве памяти Heap, а пространство памяти Stack содержит ссылку на него, когда мы создаем объект Memory в строке 4, что-то вроде Process
  • Теперь мы вызываем метод foo() в строке 5, что создаст блок в стеке для использования методом foo().
  • Java передается по значению, в строке 6 создается новая ссылка на объект Object в стеке foo()
  • В строке 7 создается объект типа string, который создает ссылку на него в памяти стека foo(), str
  • Метод foo() выполняется в строке 8. В этот момент программа освобождает пространство стека, выделенное для метода foo() в памяти стека стека.
  • В строке 9 выполняется метод main(), и стековая память, созданная для метода main(), уничтожается.В этот момент программа Java завершается, и среда выполнения Java освобождает всю память.

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

1,Жизненный цикл: память кучи используется java-приложением, и ее жизненный цикл такой же, как у jvm; память стека является частной для потока, и ее жизненный цикл такой же, как у потока.
2, Цитировать: Всякий раз, когда создается объект, он всегда сохраняется в пространстве кучи, а пространство стека содержит ссылку на него.Пространство памяти стека содержит только локальные переменные примитивных типов данных метода и ссылочные переменные объектов в пространстве кучи.
3. К объектам в куче можно получить глобальный доступ, а пространство памяти стека является частным для потока.
4. Управление структурой памяти стека jvm относительно простое, следуя принципу LIFO, а управление памятью пространства кучи относительно сложное, которое подразделяется на: новое поколение, старое поколение и т. д.
5. Жизненный цикл стековой памяти короткий, тогда как куча памяти сопровождает жизненный цикл всего приложения
6, То, как два генерируют исключения: если глубина стека запроса потока больше, чем глубина, разрешенная виртуальной машиной, исключение StackoverflowError вызовет исключение OutofMEMoryError.

3. Назначение TLAB

Буфер локального размещения потока локальный буфер выделения потока
Если задан параметр виртуальной машины -XX:UseTLAB, при инициализации потока он также будет применяться для памяти указанного размера, которая используется только текущим потоком, так что каждый поток имеет отдельное пространство. нужно выделить память, вы можете использовать ее самостоятельно. Таким образом, нет конкуренции, что может значительно повысить эффективность выделения.

4. Как выделяется объектная память

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

1.столкновение указателя: Если предположить, что память в куче Java абсолютно регулярна, вся используемая память размещена с одной стороны, свободная память размещена с другой стороны, а указатель размещен посередине как индикатор точки разграничения, то выделенная память - это просто указатель Переместите расстояние, равное размеру объекта, в сторону свободного места.
2.бесплатный список: Если память в куче Java не является регулярной, а используемая память и свободная память чередуются, виртуальная машина должна вести список, записывать, какие блоки памяти доступны, и находить достаточно большой блок из списка при выделении пространства. к экземплярам объекта, и записи в списке обновляются.

Выбор метода распределения определяется тем, является ли куча Java обычной, а регулярность кучи Java определяется тем, имеет ли используемый сборщик мусора функцию уплотнения. Следовательно, при использовании коллектора с процессом Compact, например Serial и ParNew, принятый системой алгоритм распределения — коллизия указателей; при использовании коллектора на основе алгоритма Mark-Sweep, такого как CMS, обычно используется свободный список.

Ссылаться на:nuggets.capable/post/684490… nuggets.capable/post/684490…

2.4 Какую память нужно восстановить?

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

2.5 При каких обстоятельствах проводится переработка (два метода)?

Как узнать, что объект больше не используется?

1. Подсчет ссылок

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

2.GC roots

Через ряд объектов, называемых «GC Roots» в качестве отправной точки, поиск начинается с этих узлов, а путь, пройденный поиском, называется цепочкой ссылок.Когда объект подключается к «GC Roots» без какой-либо цепочки ссылок Когда объект оказывается недоступным.

Может быть включен в качестве корневого объекта GC:

  • Ссылочный объект в стеке виртуальной машины (таблица локальных переменных во фрейме стека).
  • Объекты, на которые ссылаются статические свойства или константы (final) в области метода.
  • Объект, на который ссылается JNI (то есть собственный метод в целом) в стеке собственных методов.

2.6 Как jvm обеспечивает правильную переработку?

Коллекция поколений: разделите разные домены на основе возраста, в котором объекты выживают.

Молодое поколение: алгоритмы репликации


Старость: Отметить Алгоритм копирования:


Алгоритм сбора поколений делит область кучи на новое поколение и старое поколение, пространство нового поколения меньше, чем пространство старого поколения. Новое поколение разделено на Эдем и два пространства выживших, и их соотношение составляет 8:1:1. При создании объекта выделение памяти происходит в области Эдема нового поколения, а крупным объектам напрямую выделяется память в старом поколении.Исследования IBM показывают, что 98% объектов в области Эдема быстро умирают.

Чтобы повысить эффективность gc, в алгоритме сбора поколений разделены gc молодого поколения и старого поколения.Действие gc, которое происходит в молодом поколении, называется второстепенным gc или молодым gc, а gc, которое происходит в старом поколении называется основным gc или полным gc.

  условие срабатывания минорного gc: минорный gc возникает, когда оставшееся пространство в области Eden меньше размера памяти объекта при создании нового объекта;

  основное условие триггера gc:

   1. Явно вызвать метод System.gc();

  2.В старости места не хватает;

  3. В области метода недостаточно места;

  4.Пространство от нового поколения к старому больше, чем свободное пространство старого поколения;

Объекты в районе Эдема характеризуются коротким жизненным циклом и низкой выживаемостью, поэтому в районе Эдема для переработки объектов используется алгоритм репликации. скорость низкая, потому что нужно реплицировать объектов немного. В отличие от общего алгоритма репликации, общий алгоритм репликации может использовать только половину пространства за раз, а другая половина тратится впустую.Алгоритм восстановления области Эдема также называется алгоритмом «остановить копирование».Когда пространство области Эдема заполнена, активируйте Minor GC, очистите бесполезные объекты, а затем скопируйте уцелевшие объекты в область выжившего1 (в это время выживший0 имеет выжившие объекты, а выживший1 пуст).После очистки выживший0 остается пустым пространством, и выживший1 имеет выжившие объекты, а затем выживший0 и объект персонажа в пространстве выжившего1, повторите описанный выше процесс в следующий раз, когда сработает Minor gc. Если оставшееся место в области оставшегося в живых1 меньше места, необходимого для копирования объекта, объект выделяется старому поколению. Каждый раз, когда происходит Minor gc, возраст выжившего объекта будет увеличиваться на 1, а по достижении определенного возраста (по умолчанию 15) объект войдет в старость.

  Объекты старости в основном выживали после многократных Minor gc, поэтому они относительно стабильны и имеют высокую выживаемость.Если алгоритм репликации все же использовать, то он явно не сработает. Таким образом, старость использует алгоритм «маркировки-сортировки» для переработки объектов, тем самым повышая эффективность переработки старости.

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

2.7 Алгоритмы сборки мусора

1. Алгоритм маркировки-развертки

 Алгоритм маркировки и очистки делится на два этапа: «маркировка» и «очистка».Сначала отмечают те объекты, которые необходимо утилизировать.После завершения маркировки эти отмеченные объекты будут утилизированы.  

Недостатки: Много фрагментов; когда виртуальная машина выделяет место под объекты с большой памятью, она может не найти достаточно большого непрерывного пространства для хранения, что вызовет сборку мусора. На самом деле свободного места много, просто оно не непрерывно;

2. Алгоритм репликации

Алгоритм копирования делит память на две области одинакового размера, одна из которых используется одновременно. Когда блок памяти израсходован, объекты, которые все еще живы в этом блоке памяти, копируются в другой блок памяти, а затем блок памяти очищается.

Сейчас коммерческие jvms используют этот алгоритм для рециркуляции нового поколения, потому что объекты нового поколения в основном умирают, а уцелевших объектов около 10%, поэтому копируемых объектов меньше, этот алгоритм более эффективен.
Версия виртуальной машины с точками доступа делит динамическую память на новое поколение и старое поколение, а новое поколение далее делится на область Eden с большей памятью и две меньшие оставшиеся области. Когда память восстанавливается, выжившие объекты в области Эдема и области выживших одновременно копируются в другое пространство выживших, и, наконец, область Эдема и только что использованная область выживших очищаются. Соотношение размера eden и оставшегося пространства виртуальной машины точки доступа по умолчанию составляет 8:1, то есть доступное пространство памяти в каждом новом поколении составляет 90% (80%+10%) всего пространства нового поколения и только 10% пространства потрачено впустую. Конечно, 98% объектов, которые могут быть переработаны, являются только данными в общих сценариях.У нас нет возможности гарантировать, что не более 10% объектов переживет каждую переработку.Когда места для оставшихся в живых недостаточно, нам нужно полагаться на другую память (здесь имеется в виду старая s) сделать раздачу гарантией.

3. Алгоритмы организации маркировки

Алгоритм репликации должен выполнять больше операций репликации объектов, когда коэффициент выживания объекта высок, а эффективность будет ниже. Что еще более важно, если вам не нужно тратить 50% пространства впустую, вам нужно иметь дополнительное пространство для гарантий распределения, чтобы справиться с экстремальной ситуацией, когда все объекты в используемой памяти живы на 100%, поэтому в старости, вы не можете напрямую выбрать этот метод.

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

2.8 Сборщик мусора

1. Последовательный сборщик мусора

Кайнозой
один поток
алгоритм репликации client模式下默认的新生代垃圾收集器

2.Парновый сборщик мусора

последовательный+многопоточность

Сборщик мусора нового поколения по умолчанию в режиме сервера

3. параллельный сборщик мусора

Алгоритм многопоточной репликации
эффективный
Сосредоточьтесь на программах для достижения контроля над пропускной способностью: пропускная способность = время выполнения пользовательского кода / (время выполнения + время сборки мусора пользовательского кода)

Стратегия адаптивной настройки является важным отличием коллектора PS от коллектора ParNew.

4. серийный старый коллектор

один поток
Алгоритм сопоставления меток
Запуск на клиентской виртуальной машине java по умолчанию старости вытягивает сборщик
В режиме сервера две цели:
1. Предыдущая версия jdk15 используется с коллектором PS нового поколения;
2. Как резервная схема сборки мусора с использованием сборщика CMS в старом поколении.

  • Serial нового поколения работает в паре с Serial Old старого поколения:

  • PS нового поколения соответствует серийному номеру старого поколения:

5.параллельный старый коллектор

пс старая версия
Многопоточный алгоритм сортировки меток
До jdk1.6 ПС можно было собрать только с серийником старым;
После jdk1.6 PS сопоставляется с параллельной версией Old age:

6. Сборщик CMS: многопоточный алгоритм маркировки-развертки

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

  • Начальная отметка: отметьте объекты, с которыми могут напрямую ассоциироваться корни GC, что является быстрым и все еще требует приостановки всех рабочих потоков.
  • Параллельная маркировка: процесс отслеживания корней сборщика мусора, работа с пользовательскими потоками без приостановки рабочих потоков.
  • Переименовать:

  • Параллельная очистка

7. Коллектор G1

2.9 механизм загрузки классов Java

Загрузка класса: объект o = новый объект() Он в основном включает три этапа: загрузка через различные загрузчики классов и проверка после загрузки класса, если он включает в себя: проверку формата файла, проверку метаданных, проверку байт-кода и проверку ссылки на символ; этап подготовки предназначен для статического состояния память распределения переменных класса;

2.10 Исполнительный механизм

Как байт-код выполняется виртуальной машиной для выполнения указанной функции?

3. Как контролировать и оптимизировать GC

1. Мониторинг на основе инструмента командной строки jdk

JVM-параметры
jstat для просмотра статистики виртуальной машины
Переполнение памяти при анализе jmap+MAT
jstack анализ бесконечного цикла и взаимоблокировки

2. Визуальный мониторинг на базе JVisualVM

запускать:

Ссылаться на:Вуху.. Mommycode.com/info-detail…

3. Просмотр журнала GC для печати

Общая стратегия настройки памяти:

пример:

  public static void main(String[] args) {
     //new thread01().start();
      System.out.println(Runtime.getRuntime().maxMemory()/(double)1024/1024);//打印虚拟机最大内存,兆
      System.out.println(Runtime.getRuntime().totalMemory()/(double)1024/1024);//打印总内存
  }

Возьмите приведенный выше код в качестве примера:
Видно, что результаты равны 1797 и 123 трлн соответственно;

Установите параметры виртуальной машины jvm и общий максимальный объем памяти равными: -Xmx2G -Xms2G

Другие базовые настройки следующие:

Нативный пример печатает журнал GC:
-Xmx2G
-Xms2G
-XX:+PrintGCDetails
-XX:+PrintHeapAtGC

4. Изучение jvm, что мне это дало?

1. Понять общую модель памяти области данных Java, объявить локальные переменные и выделить память для новых экземпляров объекта.
2. Ряд изменений кадра стека в стеке java при выполнении метода.
3. Разница между стеками в jvm
4. Когда механизм сбора мусора, когда его переработка? Какой мусор рекуперируется? Каков алгоритм сборки мусора? Используйте разные сборщики мусора под разные версии.
5. Инструкции байт-кода после декомпиляции (javap -c) можно, наверное, немного посмотреть, чтобы понять, как все это дело работает шаг за шагом в jvm.
6. Мониторинг и просмотр журнала параметров ГХ.