предисловие
- Модель памяти JVM, модель памяти JAVA, объектная модель JAVA, что это за модели с похожими именами?
- Каковы наиболее часто используемые методы сбора мусора? Что такое сборщики мусора? Каковы характеристики каждого?
- Как осуществляется мониторинг JVM? Тюнинг?
- Каков внутренний формат хранения файла класса, созданного после компиляции Java?
- Каковы процессы загрузки классов? Какова модель родительского делегирования?
- В чем разница между volatile и синхронизированным?
- Что такое оптимистическая блокировка и пессимистическая блокировка? Принцип КАС?
Подробные ответы на вышеуказанные вопросы даны в книге «Углубленное понимание виртуальной машины Java».
1. История развития различных версий java
Особенности различных версий java
- Выпущена версия 1.0 в 1996 году, представляющая технологии: JVM, Applet, Awt.
- Выпущена версия 1.1 в 1997 году, представляющая технологии: формат файла jar, jdbc, javabean, внутренний класс, отражение.
- В 1998 году была выпущена версия 1.2, представляющая технологии: jit, collections
- В 1999 году была выпущена виртуальная машина HotSpot, которая позже стала виртуальной машиной по умолчанию для jdk1.3 и более поздних версий.
- Версия 1.3 была выпущена в 2000 году и представляет технологии: библиотеки классов, такие как математические операции, сервисы jndi.
- Версия 1.4 была выпущена в 2002 году и стала зрелой версией. Репрезентативные технологии: регуляризация, цепочка исключений, NIO, класс журнала, синтаксический анализ xml и т. д.
- Версия 1.5 была выпущена в 2004 году и представляет технологии: более простой в использовании синтаксис, автоматическая упаковка, дженерики, аннотации, американские сериалы, foreach, параметры переменной длины.
- Версия 1.6 была выпущена в 2006 году под названием java6. Репрезентативные технологии: оптимизация алгоритмов, таких как блокировка, синхронизация, сборка мусора и накопление значений. Объявление об открытом исходном коде
- Выпущена java7 в 2009 году, представляющая технологию: сборщик G1, обновленная архитектура загрузки классов.
- Выпущена java8 в 2014 году, версия с долгосрочной поддержкой. Репрезентативные технологии: лямбда-выражения, потоки, методы интерфейса по умолчанию и статические методы, необязательные, base64, улучшения HashMap (красно-черное дерево)
- Выпущена java9 в 2017 году, версия с краткосрочным обслуживанием. Представляющие технологии: модульная система, jshell, приватные методы интерфейсов, поддержка HTTP2 и др. Сборщик мусора CMS устарел, сборщик мусора по умолчанию — G1 (на основе однопоточного алгоритма сжатия сканирования меток)
- Выпущена версия java10 в марте 2018 г., версия с краткосрочным обслуживанием. Репрезентативная технология: var, улучшение G1 (многопоточная параллельная сборка мусора)
- Выпущена java11 26 сентября 2018 г., версия с долгосрочной поддержкой. Репрезентативные технологии: сборщик мусора нового поколения ZGC (экспериментальная стадия), JFR (мониторинг, диагностика), httpclient и др.
2. Разделение области памяти Java
1. Счетчик программ
- Индикатор номера строки байт-кода, выполняемого текущим потоком
- Каждый поток имеет независимый счетчик программ
- При выполнении метода Java запишите адрес инструкции байт-кода. Если метод Native выполняется, он пуст (не определен)
- OutOfMemoryError не появится
2. Стек виртуальных машин
- Частный поток, жизненный цикл такой же, как у потока
- Описывает модель памяти выполнения метода Java: каждый метод создает кадр стека для хранения локальных переменных, выходов метода, стеков операндов и другой информации. Каждый вызов метода соответствует кадру стека в стеке виртуальной машины в процессе стека для извлечения.
- Сохраняет основные типы данных (8 типов) и типы ссылок на объекты (указатели на адреса или дескрипторы объектов).
- Когда запрошенная глубина стека превышает допустимую глубину виртуальной машины, генерируется исключение StackOverflowError.
- Если динамическое расширение по-прежнему не может применяться для достаточного объема памяти, создается исключение OutOfMemoryError.
3. Стек собственных методов
- Функция такая же, как у стека виртуальной машины
- Разница в том, что собственный метод используется виртуальной машиной службы локального стека методов.
4. Куча
- Самый большой кусок памяти, управляемый виртуальной машиной
- Область, общая для всех потоков
- Экземпляры всех объектов находятся в этом фрагменте памяти
- Можно разделить на несколько поколений
5. Область метода
- Область, общая для всех потоков
- Хранить информацию о классе, константы, статические переменные
- Также известна как постоянная генерация на виртуальных машинах HotSpot.
- Сборка мусора в этой области происходит редко, потому что памяти для восстановления очень мало.
6. Постоянный пул времени выполнения
- является частью области метода
- Используется для хранения различных литералов и символических ссылок, сгенерированных компилятором.
7. Прямая память
- Не входит в область памяти JVM, не зависит от параметров JVM
- Когда JVM использует буфер, она выделяет память в этой области
- При настройке обратите внимание на резервирование места под эту область, вместо выделения всей памяти JVM
- -XX:MaxDirectMemorySize указан, если не указан, значение по умолчанию совпадает с максимальным размером кучи (-Xmx)
3. Объект виртуальной машины HotSpot
1. Создание объекта
-
При получении новой инструкции сначала проверьте, может ли символьная ссылка класса находиться в пуле констант
-
Да указывает, что класс был загружен, разрешен и инициализирован. В противном случае загрузите класс.
-
Распределить память кучи в соответствии с классом университета. Способ распространения такой
- Столкновение указателя: деформация памяти (без функции сжатия), только перемещение указателя. Серийный, виртуальная машина ParNew
- Свободный список: память нерегулярна (с функцией сжатия и завершения), перейдите к свободному списку, чтобы найти достаточно места. Виртуальная машина CMS
процесса распределенияПроблемы параллелизмаКак решить
- Синхронная работа: CAS+повторить
- Память предварительно выделяется для каждого потока, что называется локальными буферами выделения потока (TLAB). -XX:+/- Параметр UseTLAB определяет
-
объект инициализируется нулем
-
Установите информацию о заголовке объекта: к какому классу принадлежит объект, хэш-код объекта, возраст генерации GC, следует ли включить предвзятую блокировку и т. д.
-
Выполните метод init, чтобы выполнить инициализацию, требуемую программистом.
2. Структура памяти объекта
Расположение объектов в памяти разделено на три области: заголовок объекта, данные экземпляра, заполнение выравнивания.
2.1 Заголовок объекта
- Заголовок объекта включает в себя: данные времени выполнения самого объекта, указатель класса, к которому он принадлежит, и длину массива (если это объект массива).
- Область данных времени выполнения официально называется Mark Word.
- Область данных времени выполнения представляет собой нефиксированную структуру данных.Согласно разным битам флага содержимое хранилища отличается.
- Указатель типа указывает, к какому экземпляру класса принадлежит объект.
- Если это объект массива, он также включает длину массива
2.2 Данные экземпляра
- Достоверная информация, которую на самом деле хранит объект
- На порядок хранения влияют параметры стратегии сегментирования и порядок определения исходного кода.
- Стратегия распределения по умолчанию назначает большую длину на передний план и назначает одни и те же поля вместе.
2.3 Выравнивание отступов
- Не требуется, только заполнители
- Размер объекта должен быть целым числом, кратным 8 байтам, а недостаточный дополняется выравниванием
3. Доступ к позиционированию объектов
-
Использовать дескрипторы: куча разделяет отдельный участок памяти как пул дескрипторов, а ссылка хранит адрес дескриптора. Ссылку не нужно изменять при перемещении объекта.
-
Прямой указатель: ссылка напрямую хранит адрес объекта. высокоскоростной.
4. Сборщик мусора и стратегия распределения памяти
1. Основные понятия
1.1 Собранные объекты
куча, область памяти в области метода
1.2 Как определить, жив ли объект
подсчет ссылок
- Добавить счетчик ссылок к объекту
- Простота реализации
- Невозможно решить проблему объектов, напрямую ссылающихся друг на друга по кругу
- Используемый представитель: Microsoft COM Technology
Анализ доступности
- Используемый делегат: java, c#
- Используя объект GC roots в качестве отправной точки, когда объект недоступен, доказывается, что объект недоступен
- Корневые объекты GC включают следующие
- Объекты, на которые есть ссылки в стеке виртуальной машины
- Объект, на который ссылается статическое свойство класса в области метода
- Объект, на который ссылается константа в области метода
- Объекты, на которые ссылается JNI в собственных методах
1.3 Классификация цитат
- Сильная ссылка: операция присваивания после new является обычной, и она никогда не будет переработана, если она существует.
- Мягкие ссылки: также полезные, но не обязательные объекты. Утилизировать эти объекты перед исключением из памяти
- Слабая ссылка: слабее, чем мягкая ссылка, может существовать только до следующей сборки мусора.
- Фантомные ссылки: самая слабая связь со ссылкой. Объект не может быть получен по виртуальной ссылке. Цель существования — получать системное уведомление, когда происходит сборка мусора
1.4 Восстановление области метода (постоянная генерация)
- Эффективность сбора мусора в этом районе намного ниже, чем у молодого поколения (70%-95%).
- Перерабатывайте два типа контента: отброшенные константы, бесполезные классы.
- Условие для определения, является ли это бесполезным классом
- Все экземпляры этого класса перерабатываются
- Классовая нагрузка, которая загружает класс, перерабатывается
- Объект java.lang.Class класса нигде не упоминается и не может быть доступен через отражение
- Бесполезные классы, отвечающие вышеуказанным условиям, могут быть переработаны (не обязательно)
2. Алгоритм сборки мусора
2.1 Алгоритм маркировки-развертки
- Самый простой алгоритм сбора
- Делится на два этапа маркировки и очистки
- Недостатки:
- Вопросы эффективности
- Генерирует большое количество прерывистых фрагментов памяти
2.2 Алгоритм репликации
- Разделите память на два куска одинакового размера и используйте один за раз
- Когда блок израсходован, скопируйте уцелевшие объекты в другой блок.
- Этот алгоритм используется современными виртуальными машинами нового поколения.
- недостаточный:
- низкое использование памяти
Виртуальная машина HotSpot делит память нового поколения на большую область Eden и две меньшие области выживания. Соотношение размеров 8:1.
2.3 Алгоритмы маркировки-сопоставления
- Когда выживаемость объекта высока, большое количество копий будет влиять на эффективность, и старое поколение использует этот алгоритм.
- Процесс маркировки аналогичен алгоритму маркировки-развертки.
- Следующим шагом будет не чистка объектов, а перемещение всех уцелевших объектов в сегмент для очистки памяти за границей
2.4 Алгоритм сбора поколений
- Различные алгоритмы сбора используются в соответствии с разными жизненными циклами объекта.
- Большое количество объектов нового поколения умирает, а небольшое количество выживает, используя алгоритм репликации
- Выживаемость объектов в пожилом возрасте высока, и используется алгоритм «отметить-разметать» или «отметить-собрать».
3. Алгоритм реализации HotSpot
3.1 Перечисление корней сборщика мусора
- Когда анализ достижимости перечисляет корни GC, вы должны остановить мир.
- В настоящее время JVM использует точный сборщик мусора и не требует проверки один за другим, когда он остановлен, а напрямую извлекает его из предварительно сохраненного места. (HotSpot сохраняется в структуре данных OopMap)
3.2 Точки безопасности
- Исходя из соображений эффективности, генерация OopMap будет только в определенном месте, называемом безопасной точкой.
- Как выбрать безопасную точку
- Упреждающее прерывание: современные JVM не принимают
- Активное прерывание: поток опрашивает идентификатор безопасной точки, затем зависает
3.3 Безопасная зона
- Для потоков (спящих), которым не был выделен процессор, безопасная точка не может быть обработана и разрешается безопасной областью.
- Безопасная область означает, что ссылочное отношение в фрагменте кода не изменится.
- Когда поток входит в безопасную область, JVM не нужно заботиться об этих потоках, когда он инициирует GC.При выходе ей нужно проверить, завершен ли GC.Если он не завершен, ему нужно подождать.
3.4 Сборщик мусора
серийный коллекционер
- Самый простой и старый коллектор
- Единственный выбор для сборщика нового поколения до jdk1.3.1
- однопоточный коллектор
- Все другие рабочие потоки должны быть приостановлены во время GC
- Простой и эффективный, это хороший выбор для режима клиента с одним процессором.
Коллекционер ParNew
- Многопоточная версия серийного сборщика
- Сборщик нового поколения, предпочитаемый JVM в режиме сервера
- В однопроцессорном режиме производительность никогда не бывает лучше, чем в последовательном, из-за накладных расходов на переключение потоков.
Parallel Scavenge
- Сборщик нового поколения с алгоритмом репликации, поддерживающим многопоточность
- Пропускную способность можно контролировать
- -XX:MaxGCPauseMillis — максимальное время приостановки сборки мусора, обратно пропорциональное пропускной способности.
- -XX: Размер пропускной способности GCTimeRatio
- Обеспечивает тестирование адаптивной настройки
- -XX:UseAdaptiveSizePolicy
- Не работает сборщик CMS
Serial Old
- Версия серийного коллекционера старого поколения
- Используйте алгоритм маркировки для сопоставления
- Используется для виртуальных машин в режиме клиента
Parallel Old
- Старая версия Parallel Scavenge
- Многопоточный алгоритм пометки и сортировки
- JDK1.6 начал обеспечивать использование
Параллельная маркированная очистка (CMS)
- коллекционер старости
- Цель состоит в том, чтобы свести к минимуму паузы GC, насколько это возможно.
- Он не будет ждать, пока старое пространство не будет почти заполнено перед перезапуском (одновременно с пользовательскими потоками, оставляя память для пользовательских потоков). Параметр конфигурации -XX:CMSInitiazingOccupanyFraction.
- Используйте алгоритм маркировки и развертки. Весь процесс делится на четыре этапа:
- Начальная маркировка: STW, маркировка объектов, с которыми могут ассоциироваться корни GC, очень быстро
- Параллельная маркировка: процесс отслеживания корней GC. кропотливый. Выполнить с пользовательским потоком
- Повторная маркировка: STW, маркировка объектов, метки которых изменены программой, работающей в процессе параллельной маркировки.Время больше, чем начальная маркировка, и намного меньше, чем параллельная маркировка.
- Параллельная очистка: отнимает много времени. Выполнить с пользовательским потоком
- преимущество:
- параллельный сбор
- низкая пауза
- недостаток:
- Занять ресурсы ЦП выполняющейся пользовательской программы
- Невозможно обработать плавающий мусор (новый мусор, созданный во время параллельной очистки, не может быть удален одновременно)
- проблема с фрагментацией памяти
Сначала мусор (G1)
- Передовой сборщик мусора
- Выпущена версия jdk1.7, заменяющая CMS jdk1.5
- Структура памяти кучи отличается от других сборщиков.Старое поколение нового поколения больше не является физически изолированным, а представляет собой набор регионов.
- В соответствии со значением сбора мусора каждого региона встаньте в очередь приоритетов. Убедитесь, что каждый GC может получить максимальную скорость сбора в течение ограниченного времени
- Убедитесь, что межрегиональные регионы не требуют полного сканирования кучи с помощью параметра «Запомнить».
- бег шаг
- Начальная оценка: STW, времени очень мало. Отметьте объекты, связанные с корнями GC
- Параллельная маркировка: анализ достижимости, отнимающий много времени. Может выполняться одновременно с пользовательскими потоками
- Окончательная отметка: STW, исправьте часть изменения отметки, вызванную выполнением пользовательского потока на параллельной фазе отметки.
- Скрининг и переработка: отсортируйте стоимость переработки для каждого региона и составьте план утилизации.
- преимущество
- Параллелизм и параллелизм
- Коллекция поколений
- Дефрагментация пространства: без фрагментации памяти
- Предсказуемые паузы: сборка мусора почти в реальном времени
4. Стратегия распределения и утилизации памяти
4.1 Предметы предпочтительно размещаются в районе Эдема
-
Когда места в области eden недостаточно, JVM инициирует Minor GC.
Minor GC vs Full GC
- малая гк: кайнозойская гк, частая встречаемость, высокая скорость
- основной gc/полный gc: старческий gc, медленный
4.2 Крупные объекты входят в старость напрямую
- Типичные представители: очень длинные строки или массивы
- Большие объекты не подходят для JVM, что приводит к частому сбору мусора.
4.3 Долгоживущие объекты войдут в старость
- Объект все еще жив после первого незначительного гк Эдема, перемещен в выживший, возраст +1
- Каждый раз, когда объект проходит через младшую гк у выжившего, возраст +1
- Когда возраст добавляется к определенному уровню (по умолчанию 15), он входит в старость. Параметры: -XX:MaxTenuringThreshold
4.4 Динамическая оценка возраста
- Не всегда требуется, чтобы возраст достиг установленного значения для входа в старость
- Когда размер всех объектов одного возраста в пространстве выживших превышает половину пространства, объекты старше или равные этому возрасту сразу войдут в старость.
4.5 Гарантия распределения места
- Прежде чем выполнить минорный сборщик мусора, он проверит, превышает ли максимально доступное непрерывное пространство в старом поколении общее пространство всех объектов в новом поколении.
- Если не установлено, рассудите, больше ли он средних размеров предметов, продвинутых на старость.
- Если различные условия не выполняются, выполняется полный сбор мусора
5. Мониторинг производительности JVM
5.1 Инструменты командной строки jdk
- JPS: просмотр запущенного процесса виртуальной машины
- jstat: инструмент мониторинга статистики. Параметры:
- -class: информация о загрузке класса
- -gc: отслеживать кучу, включая eden, оставшийся в живых, старое поколение, постоянное пространство генерации, время gc и т. д.
- -gccapacity: То же, что и -gc, но основное внимание уделяется наибольшему и наименьшему пространству в каждой области.
- -gcutil: то же, что и -gc, но в основном фокусируется на проценте занятости
- -gccause: то же, что и -gcutil, но выводит причину последней сборки мусора.
- -gcnew: следить за молодым поколением
- -gcnewcapacity: то же, что и -gcnew, сосредоточиться на самом большом и самом маленьком пространстве
- -gcold: смотреть на старость
- -gcoldcapacity: то же, что и -gcold, обратите внимание на максимальное и минимальное пространство
- -gcpermcapacity: максимальное и минимальное пространство для постоянной генерации
- -compiler: информация о компиляции JIT
- printcompilation: метод JIT-компиляции
- jinfo: информационный инструмент конфигурации Java. Просмотр и настройка различных параметров виртуальных машин в режиме реального времени
- jmap: инструмент отображения памяти. Параметры:
- -dump: создать моментальный снимок хранилища кучи java
- -finalizerinfo: объект ожидает выполнения метода finalize
- -heap: отображение сведений о куче Java: период повторного использования, конфигурация параметров, статус генерации
- -histo: статистика объекта кучи: класс, количество экземпляров, общая емкость
- -permstat: состояние памяти постоянного поколения
- -F: Принудительный снимок
- jhat: анализ файлов дампа. Как правило, нет. Используйте сторонние VisualVM, eclipse, Memory Analyzer, анализатор кучи и т. д.
- jstack: инструмент трассировки стека Java, используемый для определения текущего состояния стека потоков, которые были приостановлены в течение длительного времени.
5.2 Инструменты визуализации jdk
- jconsole
- VisualVM
5. Структура файла класса
1. Обзор файловой структуры класса class
- Файл класса представляет собой набор двоичных потоков в 8-битных единицах на основе байтов.
- Каждый элемент данных строго и компактно расположен
- Данные с более чем 8-битными байтами делятся на несколько 8-битных байтов и сохраняются в порядке старших разрядов.
- Используйте хранилище псевдоструктуры, подобное структуре языка C
- Псевдоструктуры имеют два типа данных:
- Unsigned: базовый тип данных, включая u1, u2, u4, u8, число представляет количество байтов
- Таблица (составная структура): заканчивается на _info
- Порядок, количество и байты, хранящиеся в таблице ниже, строго ограничены.
2. magic
- первые четыре байта
- Определите, может ли файл класса быть принят jvm для идентификации
- Значение: 0xCAFFEBABE
3. Номер версии
- младшая версия: 5-6 байт
- основная версия: 7-8 байт
4. Постоянный пул
- Количество хранилищ ресурсов в class-файле не фиксировано, емкость постоянного пула задается типом данных u2 на входе.
- 0-й элемент пула констант пуст, цель состоит в том, чтобы некоторые из следующих значений индекса пула констант не ссылались ни на какой пул констант, а значение индекса установлено равным 0
- Существует два основных типа хранения
- Литералы: литеральные строки, конечные константы и т. д.
- Символические ссылки: полные имена классов и интерфейсов, имена и дескрипторы полей, имена и дескрипторы методов.
- Каждая константа в пуле констант представляет собой таблицу, и первый бит в начале каждой таблицы является битом идентификации типа u1, который представляет, к какому типу констант принадлежит текущая константа.
- Типы элементов постоянного пула следующие:
5. Идентификатор доступа
- два байта после константного пула
- Определяет, является ли класс обычным классом, интерфейсом, перечислением или аннотацией. государственные или частные и т. д.
6. Индекс класса, индекс родительского класса и коллекция индексов интерфейса
- Индекс класса и индекс родительского класса представляют собой данные типа u2, а индекс интерфейса представляет собой набор данных типа u2.
- Используется для определения отношения наследования этого класса
7. Коллекция полевых таблиц
- Описывает переменные, объявленные в интерфейсе или классе, за исключением локальных переменных.
- Включенная информация: область действия, статический модификатор, конечный модификатор, тип данных, volatile, переходный процесс, имя.
8. Коллекция таблиц методов
- Подобно коллекции полевых таблиц
- Включая идентификатор доступа, индекс имен, индекс дескрипторов, набор таблиц свойств
9. Коллекция листа свойств
- Собственная информация, используемая для описания определенных сценариев
- Нет ограничений по порядку, длине или содержанию, если они не дублируют существующие имена атрибутов.
6. Инструкции по байт-коду
1 Обзор
- Инструкция JVM = код операции (1 байт) + операнд
- Большинство инструкций имеют только коды операций, без операндов.
- Количество опкодов не должно превышать 256 (2^8)
- Поскольку операнды не выровнены, во время выполнения необходимо реконструировать более одного байта данных. Преимущество заключается в том, что он пропускает много отступов и пробелов, а недостаток - в потере производительности.
2. Загрузите и сохраните инструкции
- Используется для передачи данных туда и обратно между таблицей локальных переменных в кадре стека и стеком операндов.
- Загрузить локальные переменные в стек операций: iload, iload_,lload,fload,dload,aload(опорная загрузка)
- Сохранение из стека операндов в таблицу локальных переменных: istore, istore_,lstore,fstore,dstore,astore
- В стек операндов загружаются константы: bipush, sipush
3. Инструкции по эксплуатации
- Работает с двумя значениями в стеке операндов и сохраняет их обратно
- Типы byte, short, char и boolean заменяются инструкциями типа int.
- Инструкции по добавлению: iadd, ladd, fadd, папа
- Инструкции по вычитанию: isub, lsub, ...
- Инструкции по умножению: imul,...
- Инструкции отдела: idev, ...
- ...
4. Инструкции по преобразованию типов
- Преобразование расширенного типа: преобразуйте команду, не отображая ее
- in to long, float, double
- долго плавать, двойной
- плавать до удвоения
- Преобразование узкого типа: необходимо явно использовать инструкции преобразования
- В том числе: i2b, i2c, i2s, l2i...
5. Инструкции по созданию и преобразованию объектов
- Инструкция по созданию экземпляра класса: новый
- Инструкции по созданию массивов: newarray, anewarray, multianewarray
6. Инструкции по управлению стеком операндов
- Извлечь одно или два данных из верхней части стека операндов: pop, pop2
- Скопируйте верхние данные стека и поместите стек: dup, dup2
- Поменять местами верхние два элемента стека: swap
7. Инструкция по передаче управления
- Условная ветвь: IFEQ, iflt,...
- Составные условные переходы: tableswitch, lookupswitch
- Безусловный переход: goto, ret
8. Инструкции вызова и возврата метода
- Вызвать метод экземпляра объекта: invokevirtual
- Метод интерфейса вызова: invokeinterface
- Вызов специальных методов: инициализация, методы родительского класса и т. д.: invokespecial
- Вызов статического метода: invokestatic
9. Инструкции по обработке исключений
- athrow
10. Инструкции по синхронизации
- Синхронизированы соответствующие инструкции: monitorenter, monitorexit
7. Механизм загрузки классов и загрузчик классов
1. Механизм загрузки класса
1.1 Обзор
Класс начинается с загрузки в память и заканчивается выгрузкой из памяти Весь жизненный цикл включает
- нагрузка
- проверять
- Подготовить
- Разобрать
- инициализация
- использовать
- удалить
Обязательного времени загрузки класса нет, но на этапе инициализации класс необходимо инициализировать только в следующих случаях:
- При встрече с четырьмя кодами инструкций new, getstatic, putstatic и invokestatic. Соответствующий код Java: новый, установить статические поля, вызвать статические методы
- Когда пакет java.lang.reflect отражает класс
- При инициализации класса инициализируйте родительский класс, если родительский класс не был инициализирован (у интерфейса нет этого требования)
- При запуске виртуальной машины происходит инициализация основного класса (main)
- java.lang.invoke.MethodHandle конкретный результат синтаксического анализа
1.2 Загрузка
- Получить поток двоичных байтов по имени класса: источником может быть jar, war и т. д. Также это может быть сеть, прокси и т.д.
- Преобразуйте статическую структуру хранения, представленную этим потоком байтов, в структуру данных времени выполнения области метода.
- Создайте объект java.lang.Class в памяти в качестве записи доступа к классу в области методов.
1.3 Проверка
- Для того, чтобы информация, содержащаяся в потоке байтов файла класса, соответствовала требованиям виртуальной машины
- Важная работа по защите самой виртуальной машины от вредоносных атак
- Контент проверки, в частности, включает:
- Проверка формата файла: является ли магическое число 0xCAFEBABE, разрешены ли основной и дополнительный номера версий текущим jvm, правильный ли тип постоянного пула и т. д.
- Валидация метаданных: есть ли родительский класс, унаследовал ли окончательный класс, будь то не абстрактный класс реабилирует все методы и т. Д.
- Проверка байт-кода: самая сложная. Убедитесь, что данные, помещаемые в стек и из стека, относятся к одному типу, а инструкция не выходит за пределы тела метода и т. д.
- Проверка символьной ссылки: можно ли найти соответствующий класс по имени в символьной ссылке и т.д.
1.4 Подготовка
- Этап выделения памяти под переменную класса (статический тип) и установка начального значения переменной класса
- Начальное значение обычно относится к 0, а не к значению, инициализированному кодом. если только статическая переменная не указана как final
- Ниже приведены начальные значения по умолчанию.
1.5 Анализ
- Замените символические ссылки в пуле констант прямыми ссылками.
- Символическая ссылка: набор символов для описания цели ссылки, независимо от схемы памяти JVM.
- Прямая ссылка: относится к макету памяти JVM, указатель или адрес смещения, непосредственно указывающий на цель.
- Парсинг включает в себя:
- Класс или разрешение интерфейса
- разбор поля
- разбор метода класса
- Анализ метода интерфейса
1.6 Инициализация
- Действительно выполнить код Java, определенный в классе
- Процесс выполнения метода конструктора класса
- Клиентский метод получается путем объединения всех статических переменных и статического кода
- Выполнение метода безопасно в многопоточном режиме.
2. Загрузчик классов
2.1 Загрузчик классов
- Существовать вне jvm для реализации операции загрузки класса
- Любой класс однозначно определяется загрузчиком классов и самим классом
- Сравнение классов на предмет равенства имеет смысл только в том случае, если они загружены одним и тем же загрузчиком классов.
2.2 Классификация загрузчиков класса
- Запустите загрузчик классов: идентификация jvm, загрузите конкретный jar в каталог lib
- Загрузчик класса расширения: загружать банки в каталог lib/ext
- Загрузчик приложений: загрузка пользовательских классов, реализация ClassLoader, пользователи могут использовать напрямую
- пользовательский загрузчик: пользовательский загрузчик Отношения следующие:
2.2 Модель родительского делегирования
- Иерархическая связь между загрузчиками классов, показанная на рисунке, называется моделью родительского делегирования.
- Требуется, чтобы все загрузчики, кроме загрузчика класса запуска верхнего уровня, имели родительский загрузчик (реализованный композицией, а не наследованием).
- Рабочий процесс: когда загрузчик класса получает запрос на загрузку, он не будет пытаться загрузить класс сам по себе, а делегирует запрос родительскому классу для загрузки. Таким образом, все запросы будут загружены загрузчиком класса запуска в первую очередь. Когда родительский класс не может быть загружен, он загружается дочерним классом.
- Функция: убедитесь, что базовый класс является одним и тем же классом в различных загрузчиках классов, иначе система типов java будет в хаосе.
- Применение: различные службы tomcat должны быть изолированы, а общедоступные части должны использоваться повторно. Необходимо загрузить различные классы, все они реализованы через родительскую модель делегирования.
8. Механизм выполнения байт-кода JVM
1. Структура стека времени выполнения
1.1 Обзор
- Структуры данных, поддерживающие вызов и выполнение методов
- Область стека виртуальной машины Java в модели памяти jvm
- Хранит такую информацию, как таблица локальных переменных, стек операндов, динамическое соединение, адрес возврата метода и т. д.
- Вызов каждого метода соответствует процессу помещения стека в стек стека виртуальной машины.
1.2 Таблица локальных переменных
- Сохранить параметры метода и локальные переменные
- В отличие от переменных-членов класса, локальные переменные инициализируются по умолчанию.
- Индекс 0 таблицы локальных переменных хранит это по умолчанию.
1.3 Стек операндов
- Во время выполнения метода различные инструкции байт-кода помещаются и извлекаются из стека операндов.
1.4 Динамическое подключение
- Каждый кадр стека имеет ссылку на метод, которому принадлежит стек, который используется для динамического соединения.
1.5 Адрес возврата метода
2. Вызов метода
2.1 Анализ
2.2 Назначение
- статическая диспетчеризация
- Динамическая отправка
- однократная отправка и многократная отправка
- Реализация динамической диспетчеризации виртуальной машины
3. Выполнение метода
- объяснить выполнение
- Скомпилировать и выполнить
9. модель памяти Java
1. Эффективность и согласованность
- Кэш решает конфликт скорости между процессором и памятью
- Но это вводит проблему когерентности кеша
- Оптимизация процессора и перепрошивка инструкций компилятора также могут вызывать несогласованность кеша.
2. модель памяти Java
2.1 Обзор
- Особенности: построено на том, как работать с тремя характеристиками атомарности, видимости и упорядоченности в параллельных процессах.
- Функция: JVM определяет JMM для защиты различий в доступе к памяти различного оборудования и операционных систем для достижения согласованных эффектов доступа к памяти на различных платформах.
- Цель: Определить правила доступа к переменным, включая сохранение и извлечение значений переменных из памяти. Переменные здесь относятся к полям экземпляра, которые будут общими, полям класса. Не включает локальные переменные, которые не являются общими
- Условие: все переменные хранятся в основной памяти, каждый поток имеет свою собственную рабочую память, а рабочая память содержит копию переменных основной памяти. Операции с потоками над переменными должны выполняться в рабочей памяти, а не в основной памяти. Разные потоки не могут получить доступ друг к другу, и передача переменных между потоками должна проходить через основную память.
2.2 Протокол взаимодействия основной и рабочей памяти
Атомарные операции, включенные в протокол:
Как переменная копируется из основной памяти в рабочую память и как синхронизировать из рабочей памяти обратно в основную память, модель памяти Java определяет 8 операций для выполнения, каждая из которых является атомарной:
- lock: работает с основной переменной памяти, переменная принадлежит исключительно потоку
- разблокировка: работает с переменными основной памяти, разблокирована и может быть заблокирована другими потоками.
- чтение: работает с переменными основной памяти, передавая значение переменной из основной памяти в рабочую память для загрузки
- load: работает с переменными рабочей памяти и помещает значение, полученное из основной памяти операцией чтения, в копию переменной рабочей памяти
- use: роль и переменная рабочей памяти, передать значение переменной рабочей памяти механизму выполнения
- assign: роль и переменная рабочей памяти, присвоить значение исполняющего движка переменной рабочей памяти
- store: работает с переменными рабочей памяти, переменные рабочей памяти передаются в основную память для операций записи
- запись: работает с переменной основной памяти, значение, полученное при сохранении, помещается в переменную основной памяти
правила протокола
- Основная память копируется в рабочую память: чтение и загрузка должны выполняться последовательно
- Синхронизация рабочей памяти с основной памятью: сохранение и запись должны выполняться последовательно
- Не требуется непрерывное выполнение, то есть другие операции могут быть вставлены в середине
- Одна из операций чтения и загрузки, сохранения и записи не может появляться одна
- При использовании операции назначения и загрузки должны выполняться перед сохранением. То есть переменные могут рождаться только в основной памяти
- Переменная может быть заблокирована только одним потоком за раз, но один и тот же поток может быть заблокирован несколько раз, а затем разблокирован столько же раз, прежде чем его можно будет освободить.
- При выполнении блокировки значение переменной в рабочей памяти будет очищено, и ее нужно перезагрузить и присвоить при использовании.
- Разблокировка не может быть выполнена без блокировки
- При выполнении разблокировки значение переменной должно быть сначала синхронизировано обратно в основную память.
2.3 Модель памяти Java определяет специальные правила для Volatile
После того, как переменная определена как volatile, она будет иметь две характеристики:
-
Видимость: гарантирует видимость этой переменной для всех потоков. То есть, когда один поток изменяет переменную, другой поток может немедленно узнать об этом. Обычные переменные должны быть переданы через основную память для завершения.
Видимость не гарантирует безопасность параллелизма, поскольку операции могут не быть атомарными.
-
Отключите оптимизацию переупорядочения инструкций. Убедитесь, что порядок назначения переменных соответствует порядку выполнения кода.
2.4 Специальные правила модели памяти java для типов long и double
- Для 64-битных типов данных операция JVM делит чтение и запись переменных, не измененных volatile, на две 32-битные операции. то есть неатомарный контракт для длинных и двойных
- Однако JVM реализует операции с 64-битными данными как атомарные. Поэтому нет необходимости специально объявлять его как volatile
2.5 Атомарность, видимость, порядок
- Атомарность: правила модели памяти Java гарантируют атомарность доступа к примитивным типам данных. Более широкий диапазон атомарности гарантируется синхронизацией и блокировкой.
- Видимость. Модель памяти Java обеспечивает видимость за счет синхронизации нового значения с основной памятью после изменения переменной и обновления нового значения из основной памяти перед чтением переменной. Volatile гарантирует видимость переменных во время многопоточных операций, а обычные переменные — нет. Синхронизированный и окончательный также могут обеспечить видимость
- Упорядочено: этот поток отмечает, что все операции упорядочены. Смотрю один поток в другой поток, все операции идут не по порядку. Изменчивость и синхронизация обеспечивают упорядоченность операций потоков.
10. Потокобезопасность и блокировки
1. Статус потока
В любой момент времени поток имеет одно и только одно состояние
- New (Новое): состояние, которое не было запущено после создания
- Runable: запуск или ожидание, пока ЦП нарежет для него время выполнения.
- Ожидание на неопределенный срок (Ожидание): процессорное время не будет выделяться, ожидая пробуждения другими потоками. В этом состоянии появятся следующие методы
- Метод Ojbect.wait без тайм-аута
- Метод Thread.join без тайм-аута
- Метод LockSupport.park
- Ожидание по времени: процессорное время не будет выделено, но его не нужно пробуждать, система автоматически проснется через определенный период времени.
- Thread.sleep()
- Метод Ojbect.wait с тайм-аутом
- Метод Thread.join с тайм-аутом
- Метод LockSupport.parkNanos
- Метод LockSupport.parkUntil
- Заблокировано: поток входит в область синхронизации и ожидает получения состояния монопольной блокировки.
- Прекращено: завершение исполнения
2. Поточно-ориентированный метод реализации
2.1 Синхронизация взаимного исключения (блокирующая синхронизация, пессимистическая блокировка)
- Синхронизация: при одновременном доступе к данным нескольких потоков гарантируется, что только один поток будет использовать одно и то же время в одно и то же время.
- Взаимное исключение: средства для достижения синхронизации, в том числе: критическая секция (Critical Section), мьютекс (Mutex), семафор (Semaphore)
- Synchronized: самые основные средства синхронизации взаимного исключения. После компиляции инструкции monitorenter и monitorexit будут добавлены до и после кода синхронизации. При выполнении monitorenter попытайтесь получить блокировку объекта.Если вы уже владеете им, добавьте 1 к счетчику блокировок (повторный вход), в противном случае блокируйте, пока блокировка не будет снята. Блокировка вызывает ядро и требует много времени на переключение. Механизм оптимизации JVM добавит впереди ожидание вращения.
- ReentrantLock: Mutex на уровне API с некоторыми дополнительными функциями. Например, ожидание может быть прервано, могут быть реализованы справедливые блокировки и так далее. Несправедливо по умолчанию.
- Недостатки синхронизации Mutex: проблемы с производительностью при блокировке потоков и пробуждении
2.2 Неблокирующая синхронизация (оптимистическая блокировка)
- Требуется аппаратное обеспечение, чтобы гарантировать атомарность операций и обнаружение столкновений.
- CAS: сравнение и обмен, типичная неблокирующая синхронизация. включает 3 операнда
- Место в памяти: В
- Старое ожидаемое значение: A
- Новое значение: Б
- CAS использует B для обновления V только тогда, когда V соответствует A, в противном случае он не обновляется. Возвращает старое значение V независимо от того, обновлено оно или нет, процесс является атомарной операцией.
- Недостатки CAS: проблема ABA: старое значение было изменено, а затем изменено обратно и не может быть воспринято
ThreadLocal
- Некоторые переменные, к которым не нужно обращаться из нескольких потоков, используются исключительно одним потоком.
3. Оптимизация блокировки
Версия JDK1.6 реализует различные методы оптимизации блокировок для обеспечения высокого параллелизма.
3.1 Спин-блокировки и адаптивные спины
- Spinlock: когда поток ожидает, он не зависает, а выполняет цикл занятости.
- Адаптивная блокировка отжима: автоматическая настройка времени отжима в соответствии с временем последнего отжима и статусом владельца
3.2 Устранение блокировки
- Когда компилятор запускается, он автоматически обнаруживает те блокировки, которые вряд ли связаны с гонками общих данных, а затем устраняет их.
3.3 Огрубление блокировки
- Расширение серии операций синхронизации фрагментированных блокировок за пределы всей последовательности
3.4 Легкий замок
- По сравнению с традиционными блокировками, реализованными с помощью мьютексов операционной системы.
- Использование операций CAS позволяет избежать накладных расходов, связанных с использованием мьютексов.
3.5 Блокировка смещения
- Устраняет синхронизацию данных без конфликтов, что еще больше повышает производительность
- В случае отсутствия конкуренции вся синхронизация исключается, и CAS этим не занимается.