Этот блог в основном обобщает оптимизацию поздней компиляции виртуальной машины Java, модель памяти и потоки Java, безопасность потоков и оптимизацию блокировок.Резюме виртуального Java, часть 1,Сводка по виртуальной машине Java Medium.
1. Поздняя оптимизация времени выполнения
JIT-компилятор JIT
Роль JIT-компилятора заключается в преобразовании горячего кода в машинный код, связанный с платформой, и его оптимизации.Это не является необходимой частью виртуальной машины.Можно только сказать, что это вишенка на торте.
горячий код
Классификация горячего кода
- Метод вызывается несколько раз
- Тело цикла, который вызывается несколько раз
Метод обнаружения и определения горячих точек
- Обнаружение горячих точек на основе выборки, виртуальная машина периодически проверяет вершину стека и обнаруживает, что метод часто появляется на вершине стека, тогда этот метод является методом горячих точек, простым и эффективным, но неточным.
- На основе обнаружения горячих точек счетчика для каждого метода устанавливается счетчик для подсчета количества выполнений. Превышение порогового значения является методом горячих точек, и Hotpot использует этот метод. Разделяется на счетчик метода (статистический метод), счетчик возврата (статистический цикл)
Компилятор (клиентский компилятор)
- Первый этап
- Преобразование байт-кода в промежуточное представление высокого уровня (HIR)
- вторая стадия
- Конвертировать HIR в LIR
- Третий этап
- Используя алгоритм линейного сканирования, выделите регистры в LIR для генерации машинного кода.
Оптимизация
Общая оптимизация подвыражения
Когда результат выражения A вычислен и все переменные в A не изменились, то при следующем использовании A нет необходимости вычислять, а непосредственно берется предыдущий результат A.
Устранение проверки границ массива
встраивание метода
анализ побега
Определение побега: переменная, определенная в методе, переданная в качестве параметра другим методам (побег метода) или назначенная переменной класса (побег потока).
Оптимизация:
- Выделение в стеке: объекты, которые не ускользают, не размещаются в куче, а выделяются в стеке, тогда пространство, занимаемое объектом, может быть уничтожено при извлечении кадра стека, что снижает нагрузку на систему сборки мусора.
- Устранение синхронизации: если переменная определенно не ускользает от потока, то меры синхронизации для этой переменной могут быть удалены.
2. Модель памяти Java и потоки
модель памяти
Сказав так много моделей памяти, что именно является моделью памяти?
В соответствии с конкретным протоколом работы абстракция процесса доступа для чтения и записи к определенной памяти или кэшу.
Его роль заключается в определении правил доступа для каждой общей переменной в программе, то есть, как записывать переменные в память и извлекать переменные из памяти. Модель памяти Java делится на основную память и рабочую память.Все переменные хранятся в основной памяти.Потоки имеют свою рабочую память, которая является копией основной памяти.Потоки могут только читать и записывать рабочую память.
8 атомарных операций
- lock: переменная, которая воздействует на основную память и идентифицирует переменную как состояние монопольного потока.
- разблокировать (разблокировать): переменная, действующая на основную память, она освобождает переменную в заблокированном состоянии, а освобожденная переменная может быть заблокирована другими потоками.
- чтение: переменная, действующая на основную память, которая передает значение переменной из основной памяти в рабочую память потока для использования последующими действиями загрузки.
- load: переменная, которая воздействует на рабочую память и помещает значение переменной, полученное операцией чтения из основной памяти, в копию переменной в рабочей памяти.
- использование: переменная, которая воздействует на рабочую память, которая передает значение переменной в рабочей памяти механизму выполнения, который будет выполняться всякий раз, когда виртуальная машина встречает инструкцию байт-кода, которая должна использовать значение переменной.
- assign (назначение): переменная, которая воздействует на рабочую память, она присваивает значение, полученное от механизма выполнения, переменной в рабочей памяти, и выполняет эту операцию всякий раз, когда виртуальная машина встречает инструкцию байт-кода, которая присваивает значение переменной.
- store: переменная, которая воздействует на рабочую память и передает значение переменной из рабочей памяти в основную память для последующих операций записи.
- запись: переменная, которая воздействует на основную память, которая помещает значение переменной, полученное операцией сохранения из рабочей памяти, в переменную в основной памяти.
Специальные правила для volatile переменных
Характерной чертой volatile является обеспечение видимости этой переменной для всех потоков, то есть, когда значение переменной изменяется, другие потоки могут немедленно узнать об изменении. Для обычных переменных после изменения значения его нужно записать обратно в основную память, а затем другие потоки считывают данные из основной памяти. Volatile также может предотвратить переупорядочивание инструкций через барьеры памяти. Вообще говоря, его операция чтения похожа на операцию обычных переменных, а операция записи медленнее.
Специальные правила для длинных и двойных переменных
Восемь операций, как правило, являются атомарными, но для 64-битных данных модель памяти позволяет разделить операции чтения и записи 64-битных данных, которые не изменяются с помощью volatile, на две 32-битные операции ----> не- атомарное соглашение Но обычно нам не нужно объявлять long и double как volatile.
происходит до принципа
- правила порядка программы
- Правила блокировки монитора
- правила изменяемой переменной
- правило начала потока
- правила завершения потока
- Правила прерывания потока
- Правила завершения объекта
- переходность
Java и потоки
Большинство API-интерфейсов Java-класса Thread являются собственными методами, зависящими от платформы.
Три способа реализации потоков
- Реализовано с использованием потоков ядра: потоки ядра — это потоки, напрямую поддерживаемые ядром операционной системы. Ядро выполняет переключение потоков. Программа использует упрощенный интерфейс процесса, чтобы иметь отношение один к одному с потоками ядра, а затем потоки ядра направляется в ЦП через планировщик потоков.
- Реализовано пользовательским потоком: создание, синхронизация и планирование уничтожения пользовательского потока полностью выполняются в пользовательском режиме, нет необходимости переключаться в режим ядра, отношение «один ко многим».
- Пользовательские потоки + легкие процессы: отношения «многие ко многим».
планирование потоков
- совместное планирование
- Время выполнения потока контролируется самим потоком.После завершения выполнения система активно уведомляется о переключении потока, что может привести к блокировке потока на длительное время.
- упреждающее планирование
- Время распределяется системой. Потоки могут активно отдавать время, но не могут активно его получать. Порядок определяется установкой приоритетов.
состояние потока
- Новый: только что созданный, но не запущенный
- Запуск: выполнение или ожидание выделенного времени
- Бесконечное ожидание: ЦП не выделяет время, другие потоки должны просыпаться явно
- Ограниченное ожидание: система автоматически просыпается через определенное время.
- Блокировка: ожидание эксклюзивной блокировки
- конец
3. Потокобезопасность и оптимизация блокировок
Степень сохранности резьбы, в свою очередь, ослабевает.
- Неизменяемый, сделать все переменные с состоянием в объекте окончательными
- Абсолютно потокобезопасный, полностью соответствующий определению потокобезопасности
- Относительно потокобезопасные отдельные операции с этим объектом, такие как Vector, HashTable и т. д., являются потокобезопасными.
- Совместимость потока, сам объект не является безопасным потоком, но правильное использование методов синхронизации на вызывающей стороне может обеспечить нормальное использование в одновременной среде.
- Тема враждебна, независимо от усилий для решения конца, невозможно добиться безопасности потоков
Как реализовать потокобезопасность
-
Синхронизация взаимного исключения
Синхронизированное ключевое слово будет формировать инструкции monitorenter и monitorexit до и после блока кода. Этим двум инструкциям требуется параметр объекта ссылки. Блокировка имеет счетчик для достижения синхронизации. Счетчик будет +1 при входе и -1 при выходе. Это поток может повторно входить, другие потоки должны быть заблокированы и ждать. Недостатком синхронизированного режима является то, что, поскольку потоки Java отображаются на операционную систему, системе требуется помощь, чтобы разбудить и заблокировать поток, и ей необходимо переключиться из пользовательского режима в режим ядра, что потребляет много процессорного времени.
Преимущества ReentrantLock перед синхронизированным:
- дождаться прерываемого
- Справедливые замки: замки должны быть получены за один раз в том порядке, в котором они были запрошены.
- Замки связывают несколько условий
-
неблокирующая синхронизация
Чтобы решить проблемы с производительностью, вызванные блокировкой и пробуждением потока, сначала работайте с общими данными, если нет конкуренции, она будет успешной, в противном случае она будет компенсирована (повторяйте, пока не добьетесь успеха).
-
Нет схемы синхронизации
- реентерабельный код
- Локальное хранилище потоков, которое ограничивает объем общих данных потоками.
оптимизация блокировки
Схемы оптимизации блокировки следующие:
- Спин-блокировка: чтобы уменьшить потребление блокировки и пробуждения потока, поток может выполнять цикл занятости (спин), когда он заблокирован.
- Устранение блокировки: Устранение блокировок, которые не имеют конфликтов с общими данными.
- Огрубление блокировки: непрерывная блокировка и разблокировка объекта в блоке кода и блокировка всего блока кода за один раз для снижения потерь производительности.
- Облегченные блокировки: используйте операции CAS для устранения синхронно используемых мьютексов без конкуренции.
- Предвзятые блокировки: блокировки смещаются к первому потоку, который их получает.