90% Java-программистов не могут объяснить, почему код Java выполняется быстрее (2) — разогрев TLAB

Java

Я часто слышу, что производительность Java не так хороша, как C/C++, и я часто слышу, что Java-программы нуждаются в прогреве.Так в чем основная причина??

Когда дело доходит до JVM во время интервью, многие интервьюеры любят спрашивать:Почему Java-программы выполняются быстрее??

Большинство людей могут ответить, загрузка классов, прогрев кеша и т. д., но углубляйтесь,На самое главное не ответил, Сегодня эта серия статей поможет вам понять ключ к этой проблеме. Эта статья — разминка TLAB.

TLAB (Thread Local Allocation Buffer) локальный буфер выделения потока, который представляет собой область выделения памяти для конкретного потока.

image

Поскольку это область выделения памяти, мы должны сначала выяснить, как выделяется память Java.

image

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

Для реализации HotSpot JVM все реализации алгоритма GC являются разновидностью управления памятью кучи, то есть все они реализуют абстракцию кучи, и все они реализуют интерфейс CollectedHeap. При выделении пространства памяти кучи объектов CollectedHeap сначала проверяет, включен ли TLAB. Если он включен, будет предпринята попытка выделения TLAB; если размер TLAB текущего потока достаточен, он будет выделен из текущего TLAB потока; если нет , Но текущее оставшееся пространство TLAB меньше, чемМаксимальный лимит неиспользуемого пространства (это динамическое значение, которое мы подробно проанализируем позже), затем повторно подайте заявку на новый TLAB из кучи (обычно это область Eden) для выделения. В противном случае выделяйте непосредственно вне TLAB. Стратегия выделения вне TLAB, разные алгоритмы GC разные. Например, G1:

  • Если это объект Humongous (когда объект превышает половину размера Region), он размещается непосредственно в регионе Humongous (прилегающий регион старого поколения).
  • Распределить в регионе текущего индекса распределения в соответствии со статусом мутатора

Здесь нас пока интересуют только распределения TLAB. Для однопоточных приложений при каждом выделении памяти будет записываться указатель в конце адреса памяти последнего выделенного объекта, а затем выделенный объект начнет извлекать выделение из этого указателя. Этот механизм называетсяbump-the-pointer(ударник). Для многопоточных приложений при распределении памяти необходимо учитывать безопасность потоков. Самая прямая идея — пройти глобальную блокировку, но это будет очень плохой производительностью. Чтобы оптимизировать эту производительность, мы считаем, что каждый поток может выделить локальный пул памяти потока, а затем использоватьbump-the-pointerмеханизм распределения памяти. Этот локальный частный пул памяти потока называется TLAB. Только когда TLAB заполнен, когда вы подаете заявку на память, вам нужно расширить TLAB или использовать новый TLAB, а затем вам нужна блокировка. Это значительно снижает использование блокировки.

Инициализация TLAB

image

Назначение TLAB

image

Восстановление TLAB и ожидаемый размер пересчета на GC

image

Почему Java-код выполняется все быстрее и быстрее — разминка TLAB

Согласно предыдущему анализу, размер TLAB каждого потока будет изменяться и стабилизироваться в соответствии с характеристиками распределения потоков. Размер в основном определяется коэффициентом распределения EMA, но для этого получения требуется определенное количество прогонов. А первые 100 сборов EMA по умолчанию недостаточно стабильны, поэтому размер TLAB тоже часто меняется в начале программы. Когда программные потоки станут стабильными и будут выполняться в течение определенного периода времени, размер TLAB каждого потока также станет стабильным и будет скорректирован до размера, который лучше всего соответствует характеристикам выделения объектов этого потока. Таким образом, ближе к идеалу, когда только область Eden будет GC, когда она заполнена, а все объекты в области Eden эффективно распределяются через TLAB. Вот почему код Java выполняется быстрее с точки зрения TLAB.