Углубленное понимание «Углубленное понимание виртуальной машины Java»

Java

«Глубокое понимание виртуальной машины Java», отмечает

Перечитайте «Углубленное понимание виртуальной машины Java» и организуйте свои заметки в виде вопросов и ответов.

Как распределяется область памяти Java?

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

счетчик команд: Относительно небольшой объем памяти, который можно использовать в качестве индикатора номера строки байт-кода, выполняемого текущим потоком. Потому что при многопоточности потоки переключаются по очереди и выделяется время выполнения ЦП. Ядро в любой момент может выполнить только одну инструкцию. Таким образом, для того, чтобы поток переключался туда и обратно и продолжал выполнять инструкции из правильного места, необходим счетчик программ. В то же время эта память является частной для каждого потока. Кроме того, если поток выполняет метод Java, счетчик записывает адрес инструкции байт-кода. При выполнении собственного метода значение счетчика пусто. Эта область является единственной областью в Спецификации виртуальной машины Java, в которой не указаны какие-либо условия OOM.

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

таблица локальных переменных: Хранит различные основные типы данных виртуальной машины Java, известные во время компиляции, ссылки на объекты и типы returnAddress (указывающие на адрес инструкции байт-кода). Вызовет исключение переполнения стека и исключение OOM.

собственный стек методов: функция стека виртуальной машины очень похожа, разница в том, что стек виртуальной машины обслуживает java-метод, а локальный стек методов обслуживает нативный метод.

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

область метода: Используется для хранения таких данных, как информация о типах, константы, статические переменные и кэши кода, скомпилированные JIT-компилятором, которые были загружены виртуальной машиной. Также входит в область методапостоянный пул времени выполнения. В дополнение к информации описания версии класса, поля, метода, интерфейса и т. д., файл класса также имеет постоянную таблицу пула, которая используется для хранения различных литералов и расширенных ссылок, сгенерированных во время компиляции.Эта часть содержимого будет быть загружен после загрузки класса.Хранится в пуле констант времени выполнения области методов.

Как понять ЖММ?

Модель памяти Java: Спецификация, определяющая, как JVM использует память компьютера. Вообще говоря, он разделен на две части: структура памяти JVM и JMM и спецификация потоков.

JMM в основном используется для управления взаимодействием потоков между Java и определения того, когда запись потока в общую переменную видна другому потоку (определение абстрактной связи между потоками и основной памятью).

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

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

означает: Внутренний (под один поток): принцип «происходит до» Внешний (под многопоточность): различные механизмы синхронизации (volatile, lock, final, synchronize и т.д.)

Эту часть деталей можно найти в другой статье:БЛОГ PRIK - Глубокое понимание модели памяти Java

Каков процесс создания объекта Java? ?

  1. Когда виртуальная машина встречает новую инструкцию байт-кода, она сначала проверяет, может ли параметр инструкции найти символическую ссылку на класс в пуле констант, и определяет, был ли загружен, разрешен и инициализирован класс, представленный этой ссылкой. Если нет, то сначала необходимо выполнить соответствующий процесс загрузки класса.
  2. После того, как проверка загрузки класса пройдена, пора выделить память. Размер памяти, необходимый объекту, можно определить после загрузки класса. Выделение памяти объекту эквивалентно отделению целого блока памяти от кучи Java. На данный момент есть две ситуации:
    1. Если куча памяти абсолютно полная, то просто переместите указатель на границу между используемой и неиспользуемой памятью в сторону. Этот метод распределения становится коллизией указателя.
    2. Если память кучи не полностью опрятна, виртуальная машина должна поддерживать список для записи доступной памяти и ее размера. При выделении памяти вам нужно найти в списке достаточно большой объем памяти, чтобы разделить экземпляр объекта, и обновить список. Этот путь становится свободным списком.
    Выбор метода нераспределения зависит от того, аккуратна ли память кучи, а аккуратность памяти кучи зависит от того, имеет ли сборщик мусора возможность сжатия. Сборщики, такие как Serial и ParNew, имеют процесс уплотнения и могут использовать столкновение указателей. CMS, сборщик, основанный на алгоритме маркировки и очистки, теоретически может использовать только метод свободного списка.
  3. Также необходимо учитывать вопросы безопасности потоков. В случае параллелизма многие операции небезопасны для потоков. Есть два решения:
    1. CAS+ не может повторить попытку, чтобы обеспечить атомарность операций обновления.
    2. Буфер локального размещения потока TLAB. У каждого потока есть небольшой участок памяти, который принадлежит только ему самому.Когда эта часть израсходована, он синхронизируется с блокировкой для выделения памяти.
  4. Затем необходимо инициализировать выделенное пространство памяти (кроме заголовка объекта) нулевым значением (нулевое значение, соответствующее типу данных), чтобы обеспечить возможность использования полей java-объекта в коде без присвоения начального значения .
  5. Установите заголовок объекта. Этот объект является экземпляром какого класса, как найти информацию о метаданных класса, хэш-код объекта (вычисляется только при вызове метода hashCode()), возраст создания GC объекта и т. д. и сохраните его в заголовке объекта.
  6. На данный момент с точки зрения виртуальной машины объект создан. С точки зрения программиста создание объектов только началось. Потому что конструктор еще не выполнен. Также необходимо выполнить () в файле класса, то есть конструкторе, чтобы объект был построен в соответствии с нашими пожеланиями, и был создан действительно пригодный для использования и полный объект.

Из каких частей состоит объект Java? Какая информация хранится отдельно?

Объект Java состоит из 3 частей: заголовка объекта, данных экземпляра и заполнения выравнивания.

  1. заголовок объекта. Заголовок объекта хранит две части информации. Первая часть — это данные времени выполнения самого объекта, такие как хэш-код, возраст генерации GC, флаг состояния блокировки, блокировки, удерживаемые потоками, смещенный идентификатор потока, смещенная временная метка и т. д. Длина этой части данных составляет 32 бита или 64 бита (в зависимости от количества бит виртуальной машины). Чтобы улучшить использование пространства, он разработан как динамическая структура данных. Храните как можно больше данных на очень маленьком пространстве. В зависимости от состояния объекта хранимая информация имеет различный смысл. Вторая часть — это указатель типа. Это указатель на метаданные типа объекта, и виртуальная машина использует этот указатель, чтобы определить, экземпляром какого класса является объект.
  2. данные экземпляра. То есть информацию об объектах, которые мы реально храним, различные поля, определенные в коде, и т. д.
  3. Выровнять отступы. Заполнитель. Система автоматического управления памятью виртуальной машины HotSpot требует, чтобы размер объекта был целым числом, кратным 8 байтам. Заголовок объекта был точно спроектирован таким образом, чтобы его размер в один или два раза превышал 8 бит.Если часть данных экземпляра объекта не выровнена, для ее завершения требуется дополнение выравнивания.

Как виртуальная машина находит местоположение объекта Java? Сколько существует способов? Каковы преимущества и недостатки каждого из них?

Программы Java работают с определенными объектами в куче через справочные данные в стеке. Есть два основных метода: дескрипторы и прямые указатели.

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

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

Как определить, является ли объект мусором, который необходимо собрать? Как происходит процесс сбора мусора?

Сборка мусора должна сначала ответить на три вопроса:

  1. Какую память нужно восстановить?
  2. Когда перерабатывать?
  3. Как переработать?

Оценка того, какая память должна быть переработана, — это оценка того, какие объекты мертвы (больше не нужны) Существует два основных метода:

  1. подсчет ссылок: Добавляет к объекту счетчик ссылок, который увеличивается на единицу при наличии локальной ссылки. Когда ссылка становится недействительной, счетчик уменьшается на единицу. Любой объект с нулевым счетчиком больше не используется. Хотя этот метод прост в принципе и обладает высокой эффективностью, он не был принят в основных виртуальных машинах Java. Причина в том, что этот обманчиво простой алгоритм имеет много исключений, которые нужно учитывать, и требует много дополнительной обработки для правильной работы. Например, простой подсчет ссылок трудно решить проблему циклических ссылок между объектами.
  2. Алгоритмы анализа достижимости: Основная идея состоит в том, чтобы использовать ряд корневых объектов, которые становятся «Корнями GC», в качестве начального узла и выполнять поиск вниз в соответствии с эталонным отношением. Если у объекта нет возможности достичь корней GC, это означает, что объект из GC Roots для этого объекта. Недостижимый, что доказывает, что объект больше не используется.

Объекты, которые определены как недостижимые при анализе достижимости, не сразу удаляются сборщиком мусора. Если обнаружится, что он недоступен, он будет помечен в первый раз, а затем снова будет отфильтрован, условием является необходимость выполнения объектом метода finalize(). Если объект не переопределил метод или был вызван и выполнен виртуальной машиной, его выполнение считается излишним. Объекты, которым необходимо выполнить этот метод, помещаются в очередь, а затем виртуальная машина автоматически создает поток с низким приоритетом планирования для выполнения их метода finalize(). Виртуальная машина гарантирует запуск этого метода только для начала выполнения и не обещает дождаться его завершения. Кроме того, метод finalize() официально объявлен устаревшим. Использование try-finally является лучшим подходом.

Какие ссылочные типы существуют в Java?

После JDK1.2 в Java ссылки делятся на сильные ссылки, мягкие ссылки, слабые ссылки и виртуальные ссылки.

сильная цитата: Проще говоря, самая традиционная ссылка — это ссылка на новый объект. В любом случае, пока существует сильная ссылочная связь, сборщик мусора никогда не вернет объект, на который указывает ссылка.

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

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

фантомная ссылка: Также называемая фантомной ссылкой, это самая слабая связь ссылки. Независимо от того, существует ли у объекта виртуальная ссылка, это никак не повлияет на его время жизни, и невозможно получить экземпляр объекта через виртуальную ссылку. Единственной целью установки фиктивной ссылки на объект является отправка системного уведомления до того, как объект будет собран сборщиком мусора. Реализация PhantomReference.

Что такое сборка мусора в области методов?

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

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

  1. Все экземпляры этого класса переработаны, и в куче java нет экземпляров этого класса и каких-либо производных подклассов.
  2. Загрузчик классов, который загружал класс, был переработан.
  3. Java.lang.Classs, соответствующие объекту класса, нигде не упоминаются, к ним нельзя получить доступ через отражение.

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

В сценариях, где используется большое количество фреймворков байт-кода, таких как отражение, динамический прокси, CGLib, и часто динамически генерируются пользовательские загрузчики классов, такие как JSP, виртуальная машина Java обычно должна иметь возможности выгрузки типов, чтобы гарантировать, что она не будет привести к слишком большому повреждению области метода.нехватка памяти.

Что такое поколенческая коллекция?

Большинство сборщиков мусора современных коммерческих виртуальных машин разработаны в соответствии с теорией «сборки поколений». Теория поколенческой коллекции основана на двух гипотезах:

  1. гипотеза слабого поколения: подавляющее большинство объектов эфемерны
  2. Гипотеза сильного поколения: Объекты, пережившие большее количество сборок мусора, труднее умереть.

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

  1. Если большинство объектов в области умирает, вам нужно сосредоточиться только на нескольких уцелевших объектах при восстановлении этой области, вместо того, чтобы отмечать множество объектов, которые необходимо восстановить, чтобы можно было восстановить большое количество пространства с более низкими затратами. Стоимость.
  2. Если область состоит в основном из трудноудаляемых объектов, то эту область можно собирать с меньшей частотой, принимая во внимание затраты времени на сборку мусора и эффективное использование памяти.

Есть еще одна проблема:межпоколенческие цитаты. Если выполняется дополнительный сборщик мусора, на объекты в молодом поколении может ссылаться старое поколение, поэтому необходимо просмотреть все объекты во всем старом поколении, чтобы убедиться в правильности результата анализа достижимости. Очевидно, что это сильно влияет на производительность.

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

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

Каковы некоторые распространенные алгоритмы сборки мусора? Каковы их соответствующие принципы?

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

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

алгоритм пометки-копииАлгоритм копирования половинной области: используйте два блока доступной памяти одинакового размера и используйте только один из них за раз.Когда один блок израсходован, скопируйте объекты, которые все еще живы, в другой блок памяти, а затем очистите его. блок памяти. Если это старое поколение, оно будет генерировать много накладных расходов на копирование объектов. Если это новое поколение, его просто внедрить и эффективно использовать. А вот недостаток очевиден, то есть утилизация памяти невысокая. Большинство современных коммерческих виртуальных машин используют эволюционную версию этого метода: новое поколение разделено на большее пространство Eden и два меньших пространства Survivor. Для каждого выделения памяти используются только Иден и один из выживших. Когда происходит сборка мусора, объекты, все еще живые в Eden и Survivor, одновременно копируются в другое пространство Survivor, а затем очищаются. Соотношение размеров HotSpot по умолчанию равно Eden: Survivor = 8 : 1. Во избежание некоторых ситуаций Survivor недостаточно для размещения уцелевших объектов, и он также будет полагаться на другую региональную память (старого поколения) для гарантированного распределения.

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

Как теория коллекций поколений решает проблему межпоколенческого цитирования? Что такое набор памяти? Что такое карточный стол? Как обслуживается карточный стол?

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

Запоминаемый набор — это структура данных, которая записывает набор указателей из области, не являющейся коллекцией, в область коллекций. Принимая во внимание затраты на хранение и обслуживание, нет необходимости иметь точность запомненного набора с точностью до каждого указателя. В итоге была выбрана точность карты:Каждая запись точна для небольшой области памяти, с одним или некоторыми объектами, содержащими кросс-поперечные указатели.. Такая реализация называетсякарточный стол(карточный стол). Базовая структура данных представляет собой массив байтов. Каждый элемент соответствует блоку памяти определенного размера в области памяти, которую он представляет. Этот блок памяти называется страницей карты. На каждой странице карточки есть несколько объектов. Пока один объект содержит указатель перекрестного поколения, он помечен как 1, а другие помечены как 0. Во время сборки мусора, пока элементы, помеченные как 1 в таблице карточек, отфильтрованы, легко найти те страницы карточек, которые содержат указатели перекрестного поколения, и добавить их в корни GC для совместного сканирования.

Так как же поддерживается состояние карточного стола?

Виртуальная машина HotSpot поддерживает таблицу карт с помощью технологии барьера записи. Барьер записи можно рассматривать как АОП-аспект операции «назначения поля ссылочного типа» на уровне виртуальной машины. Когда эталонный объект назначается, генерируется объемное уведомление, и эту функцию можно использовать для ведения таблицы карт.

Как гарантируется корректность анализа достижимости в параллельной среде?

При анализе достижимости карта объектов должна быть пройдена на основе непротиворечивого снимка. В противном случае это может привести к тому, что объект, который изначально должен быть сохранен, будет помечен как выполненный. Например, при анализе объекта B, на который ссылается объект A, помеченный как смерть, метка B мертва, но затем B теперь сканируется, помечается как живой объект C, ссылается на него и не сканирует его повторно. , поэтому объект B, который должен выжить, будет собран мусором.

Для решения проблемы исчезающих объектов есть два решения.

Инкрементное обновление: Когда объект, который был отсканирован и помечен как активный, вставляется в новую связь ссылок, указывающую на объект, помеченный как мертвый, запишите ссылку, а после завершения одновременного сканирования добавьте оставшиеся объекты в записанную связь ссылок. Для корня , отсканируйте еще раз.

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

Каковы общие сборщики мусора? Как все это работает?

Серийный коллекционерСамый простой и старый сборщик, использующий алгоритм маркировки-копии. Единственный выбор для ранних коллекционеров молодого поколения. Однопоточная работа, и когда происходит сборка мусора, все остальные рабочие потоки должны быть приостановлены до окончания сбора. Но у него есть то преимущество, что он прост и эффективен, и у него наименьшее дополнительное потребление памяти среди всех сборщиков мусора.Это сборщик молодого поколения по умолчанию, работающий в клиентском режиме. Кроме того, для одноядерного процессора один поток не имеет накладных расходов на переключение потоков, и эффективность сбора выше. Он имеет лучшие приложения для работы в клиентском режиме (настольные приложения). Для молодого поколения с небольшим объемом памяти время паузы для сборки мусора можно полностью контролировать в пределах от десяти до десятков миллисекунд.

Серийный старый коллекционерВерсия сборщика серийных номеров старого поколения. одиночная нить. Используйте алгоритм маркировки для сопоставления. Он также в основном используется для виртуальных машин в режиме клиента. Он также используется на стороне сервера: он используется со сборщиком Parallel Scavenge в предыдущих версиях JDK5, а также используется в качестве резервного сборщика для CMS, когда в параллельном сборе происходит сбой параллельного режима.

Коллекционер ParNewМногопоточная версия сборщика Serial явно превосходит сборщик Serial для многоядерных процессоров.

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

Параллельный сборщик OdВерсия параллельного коллектора старого поколения. Многопоточность. Алгоритм маркировки-сопоставления. Также обратите внимание на пропускную способность.

Сборщик CMSПоскольку целью является кратчайшее время паузы для восстановления, время паузы системы должно быть как можно короче, чтобы предоставить пользователям наилучшие интерактивные возможности. Процесс сбора разделен на четыре этапа: 1. Начальная маркировка -> 2. Параллельная маркировка -> 3. Перемаркировка -> 4. Параллельная очистка. Stop The World требуется для первоначальной маркировки и повторной маркировки. Начальная метка предназначена только для маркировки объектов, с которыми GC Roots может напрямую ассоциироваться, что очень быстро. Параллельная маркировка — это процесс обхода всего графа объектов, начиная с непосредственно связанных объектов корней GC. Перемаркировка предназначена для исправления некоторых объектов (инкрементных обновлений) отмеченных изменений, вызванных тем, что пользовательский поток продолжает выполняться во время параллельной маркировки, с немного большей паузой. Наконец, существует параллельная фаза очистки. Но есть три явных недостатка:

  1. Сборщик CMS очень чувствителен к ресурсам процессора. Занимает часть вычислительной мощности процессора, поэтому общая пропускная способность снижается.
  2. Неспособность собрать плавающий мусор может привести к полной сборке мусора. Во время фаз параллельной маркировки и одновременной очистки система все еще работает нормально, поэтому необходимо зарезервировать некоторую память для использования системой. Если зарезервированная память не может удовлетворить потребности вновь выделенной памяти программы, происходит сбой параллельного режима. В это время виртуальная машина включает резервную схему, замораживает пользовательский поток и временно разрешает сборщику Serial Old снова выполнять сборку мусора старого поколения. Это сделает паузу дольше.
  3. Поскольку это алгоритм очистки тегов, в конце генерируется большое количество фрагментов. Иногда он заранее развертывает полный сборщик мусора.

Первый сборщик мусораколлектор Г1. веха. Создал идею ориентированного локального сбора и формы размещения памяти на основе региона. Получите максимально возможную пропускную способность с управляемой задержкой. Сборщик G1 делит непрерывную кучу Java на несколько независимых регионов одинакового размера, и каждый регион может играть роль пространства Eden, пространства Survivor или старого пространства нового поколения по мере необходимости. Существует также тип Огромной области, которая используется для хранения больших предметов, что в основном эквивалентно старости. Сборщик G1 отслеживает стоимость мусора в каждом регионе, то есть размер пространства, полученного в результате высвобождения, и время, необходимое для высвобождения. Список приоритетов будет поддерживаться в соответствии со значением, и каждый раз область с наибольшим значением будет предпочтительно восстанавливаться в соответствии с допустимым временем паузы сбора, установленным пользователем. Гарантируется, что G1 может получить максимально возможную эффективность сбора за ограниченное время. Каждый регион поддерживает свой собственный набор памяти для разрешения межрегиональных ссылок. Следовательно, он будет занимать больше памяти (от 10% до 20% памяти кучи). В отличие от CMS, которая использует алгоритм добавочного обновления для реализации параллельного сбора, G1 использует для его реализации исходный алгоритм моментальных снимков. Процесс сбора:

  • Начальная отметка: отметьте объекты, с которыми можно напрямую связать корни GC.
  • Маркировка параллелизма: параллельный анализ достижимости
  • конечная метка: короткая пауза для обработки нескольких объектов, оставшихся в конце параллельной метки (исходный снимок)
  • Скрининг для переработки: обновление статистики региона, сортировка по стоимости и стоимости моделей переработки, а также разработать планы переработки на основе ожидаемых пользователей. Выберите любое количество регионов для формирования коллекции, скопируйте выжившие объекты в пустую область и очистите все старые пространство региона. Процесс перемещения объекта должен приостановить пользовательскую поток. И это выполняется одновременно несколькими коллекционными нитьми.

G1 против системы управления контентомПо опыту лучше CMS ниже 6-8G, выше G1. В дальнейшем G1 постепенно избавится от CMS. Объем памяти и загрузка процессора у G1 выше, чем у CMS. И полностью заменить существование CMS сейчас невозможно.

Сравнение коллекторов

коллекционер параллельно Применимая область алгоритм Цель Применимая сцена
Serial сериал Кайнозой алгоритм репликации Приоритет скорости отклика Клиентский режим под одним процессором
Serial Old сериал старость Отметить-организовать Приоритет скорости отклика План резервного копирования в режиме клиента/CMS на одном ЦП
ParNew параллельно Кайнозой алгоритм репликации Приоритет скорости отклика Режим сервера и Multi-CPU с CMS
Parallel Scavenge параллельно Кайнозой алгоритм репликации приоритет пропускной способности Работает в фоновом режиме с меньшим взаимодействием
Parallel Old параллельно старость Отметить-организовать приоритет пропускной способности Работает в фоновом режиме с меньшим взаимодействием
CMS параллелизм старость отметить - очистить Приоритет скорости отклика Он сосредоточен в Java-приложении интернет-сайта или системного сервера B/S.
G1 параллелизм both Отметить-организовать + скопировать Приоритет скорости отклика Для серверных приложений замените CMS

Общие комбинации коллекторов:

  1. Serial + Serial Old реализует однопоточную сборку мусора с малой задержкой.
  2. ParNew + CMS реализует многопоточную сборку мусора с малой задержкой
  3. Parallel Scavenge + Parallel Scavenge Old для многопоточной высокопроизводительной сборки мусора

Как правильно выбрать сборщик мусора

Нужно попробовать больше в соответствии с реальной ситуацией, руководящий принцип:

  1. Если система учитывает приоритет пропускной способности, ресурсы ЦП используются для обработки бизнеса в наибольшей степени, и используется Parallel GC.
  2. Если система считает низкую задержку, время каждого GC должно быть как можно короче, используйте CMS GC
  3. Если память системной кучи велика и вы хотите, чтобы общее среднее время сборки мусора можно было контролировать, используйте G1 GC.

Из соображений памяти:

  1. Выше 4G G1 GC более экономичен
  2. Если он превышает 8G и достигает памяти 16-64G, настоятельно рекомендуется G1 GC.

Что такое сборщик мусора по умолчанию для каждой версии JDK?

Раньше Java8 был Parallel GC, а после Java9 он был изменен на G1 GC.

Как происходит процесс загрузки класса? Что делает каждый этап?

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

1. Загрузить

  1. Получите поток двоичных байтов, определяющий этот класс, назвав его с разрешения класса. (Есть много трюков, шифрование, сбор данных по сети, генерация вычислений, чтение базы данных) Если не найдено, выдает NoClassDefFoundError
  2. Преобразуйте статическую структуру хранения, представленную этим потоком байтов, в структуру данных времени выполнения области метода.
  3. Объект java.lang.Class, представляющий класс, создается в памяти как запись доступа к различным данным этого класса в области методов.

2. Проверка

  1. формат файла. Начинается ли магическое число с 0xcafebabe, подходит ли номер версии для виртуальной машины и т. Д.
  2. Метаданные. Соответствует ли это нормам языка Java
  3. байт-код. Законна ли семантика?
  4. Символическая ссылка. Доступ к требуемым внешним классам, методам и т. д. отсутствует или запрещен.

(VerifyError, ClassFormatError, UnsupportedClassVersionError)

3. ПодготовьтеВыделить память для переменных (статических переменных), определенных в классе, установить начальные значения.

4. АнализЗамените ссылку на символ в пуле констант на прямую ссылку.

5. ИнициализацияВыполнить метод конструктора класса(). Он генерируется компилятором, который автоматически собирает присвоение всех переменных класса в классе и объединяет операторы в статический блок операторов. (Обратите внимание, что он собирается по порядку, операторы в статическом блоке операторов не могут получить доступ к переменным, определенным после блока операторов) В JVM четко оговаривается, что инициализация класса должна выполняться при первом активном использовании класса.

Какова модель родительского делегирования? Какие типы загрузчиков классов существуют в Java? Какова роль каждого?

Модель родительского делегированияРабочий процесс таков: если загрузчик класса получает запрос на загрузку класса, он не будет пытаться загрузить его сам, а сначала делегирует его загрузчику родительского класса. Таким образом, все запросы на загрузку классов будут переданы загрузчику классов верхнего уровня. Только когда родительский загрузчик не может выполнить запрос на загрузку (не найден), дочерний загрузчик попытается выполнить его. (КлассНофундИсключение)

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

С точки зрения виртуальной машины существует только два разных загрузчика классов: загрузчик запускаемого класса и другой загрузчик классов.

Запустите загрузчик классов: реализован на C++ и является частью самой виртуальной машины. Он отвечает за загрузку классов, хранящихся в каталоге /lib или хранящихся по пути, указанному в параметре -Xbootclasspath, и распознаваемых виртуальной машиной Java (идентифицируемой по имени, например, rt.jar, если имя не не совпадают, он не будет загружен). Java-программа не может напрямую ссылаться на него. Если пользовательский загрузчик классов необходимо делегировать загрузчику запускаемых классов, просто используйте вместо него значение null.

загрузчик класса расширения: Отвечает за загрузку классов в каталог /lib/ext. Или все библиотеки классов по пути, указанному в системной переменной java.ext.dirs.

загрузчик класса приложения: отвечает за загрузку всех библиотек классов по пути к классам. Загрузчик классов приложения можно получить с помощью ClassLoader.getSystemClassLoader(). Если пользовательский загрузчик классов не используется, из него загружаются пользовательские классы.

пользовательский загрузчик классов

Как виртуальная машина выполняет оптимизацию блокировки? Какие типы замков существуют?

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

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

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

Легкий замокИспользуйте реализацию заголовка объекта Mark Word.

Для экономии места Mark Word сохраняет различную информацию, когда объекты находятся в разных состояниях. Например, хэш-код, возраст поколения GC и т. д. Когда объект заблокирован, есть 2 бита для хранения бита флага блокировки, а 1 бит равен 0, что указывает на то, что режим смещения не введен.

Когда код собирается войти в блок синхронизации, если объект синхронизации не заблокирован (флаг блокировки равен 01), виртуальная машина создаст пространство с именем Lock Record в кадре стека текущего потока для хранения копии объекта синхронизации. Текущее слово маркировки объекта. Затем используйте CAS, чтобы обновить слово пометки до указателя на запись блокировки. Если обновление прошло успешно, это означает, что поток владеет блокировкой этого объекта и изменяет флаг блокировки в Mark Word на «00», указывая на то, что он находится в состоянии облегченной блокировки.

Если обновление не удается, это означает, что другой поток получил блокировку. Текущий поток входит в цикл и продолжает попытки получить облегченную блокировку. Если она не будет получена через определенный период времени, облегченная блокировка будет расширена до тяжелой блокировки (измените информацию заголовка объекта на усиленную блокировку: указатель на усиленную блокировку + бит флага 10) и приостановите ожидание.

Когда легкий замок освобожден, также нам нужно CAS, сохраненное слово обновление слова. Если обновление успешно, синхронизация успешно завершена. Если обновление не удается, то последний шаг Существуют другие потоки, также хотят получить блокировку, блокировку инфляции в тяжелом весе. Хотя необходимо отпустить замок, разбудить подвесную нить.

Следует отметить, что облегченные блокировки могут повысить производительность, основываясь на опыте, что «для большинства блокировок нет конкуренции в течение всего цикла синхронизации». CAS позволяет избежать накладных расходов на использование мьютексов. Если большую часть времени имеет место конфликт за блокировку, в дополнение к служебным затратам мьютекса, которые изначально требуются, служебные данные операции CAS будут больше, но служебные данные будут еще больше.

Блокировка смещенияЦель: повысить производительность за счет устранения примитивов синхронизации в неконкурентном случае. Если поток получает смещенную блокировку, поток, удерживающий смещенную блокировку, никогда не будет нуждаться в повторной синхронизации при отсутствии конкуренции со стороны других потоков. Как только другой поток пытается получить блокировку, смещенный режим завершается. Если объект разблокирован, смещение отменяется (бит смещения устанавливается в 0) и восстанавливается до разблокированного состояния (бит флага 01). Если объект заблокирован, смещение меняется на противоположное и выполняется облегченная блокировка (флаг 00). Если к большинству блокировок обращаются несколько разных потоков, то смещенный режим на самом деле является избыточным. Блокировка смещения может быть отключена параметром.

Что такое спин-блокировка? Что такое адаптивный спин?

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

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

Что такое анализ побега? Какая польза?

Самый основной принцип escape-анализа – анализ динамической области действия объекта. Когда объект определен в методе, на него могут ссылаться внешние методы, например, передавать его в качестве параметра вызова другим методам. Этот метод именования экранирует . К нему также может обращаться внешний поток, который называется выходом из потока. Без побега, побег метода, побег потока, различные степени побега от объектов с низким и высоким адресом.

Если можно доказать, что объект не выйдет за пределы метода или потока (т. ), то можно брать разные степени оптимизации:

  1. Выделение в стеке. Выделение памяти в куче — ресурсоемкая операция как для повторного использования, так и для сортировки. Если вы уверены, что объект не ускользнет из потока, рекомендуется разместить объект в стеке. Пространство памяти, занимаемое объектом, может быть уничтожено при извлечении кадра стека. Таким образом, на сборщик мусора оказывается намного меньше нагрузки.
  2. Скалярная замена: если данные больше не могут быть разложены на более мелкие данные для отображения, такие как примитивные типы данных в виртуальной машине Java, ссылочные типы и т. д., такие данные называются скалярными. Объект Java противоположен скаляру, агрегату. В зависимости от ситуации доступа к программе разрешенные переменные-члены восстанавливаются до их исходных типов для доступа.Этот процесс называется скалярной заменой. Если escape-анализ доказывает, что доступ к объекту вне метода невозможен и объект может быть демонтирован, то программа может не возвращаться к созданию объекта при его фактическом выполнении, а вместо этого напрямую создавать некоторые из своих переменных-членов, используемых методом. метод вместо этого. Это может создать условия для последующей дальнейшей оптимизации.
  3. Синхронное удаление: синхронизация потоков является относительно тяжелой операцией. Если анализ Escape доказал, что переменная не избежит нити, затем прочитайте эту переменную, не будет иметь конкуренцию, синхронизированные меры для реализации этой переменной будут безопасно устранены.

следите за моим блогом

trzoey.github.io/blog-prik/