Влияние Java потоков с точки зрения G C или обработки недолговечных объектов с помощью GC - PullRequest
5 голосов
/ 13 января 2020

В Интернете есть несколько статей, в которых упоминаются некоторые недостатки использования Stream -s по сравнению со старыми loop -s:

Но есть ли какое-либо влияние с точки зрения G C? Как я предполагаю (это правильно?), Что каждый вызов потока создает некоторые недолговечные объекты внизу. Если конкретный фрагмент кода, который использует потоки, часто вызывается базовой системой, может ли это в конечном итоге вызвать проблемы с производительностью с точки зрения G C или оказать дополнительное давление на G C? Или воздействие минимально и может игнорироваться большую часть времени?

Есть ли какие-нибудь статьи, освещающие это подробнее?

1 Ответ

1 голос
/ 15 января 2020

Если честно, очень сложно дать ответ, когда Хольгер уже связал основную идею с помощью своего ответа; Тем не менее я постараюсь.

Дополнительное давление на G C - может быть. Дополнительное время для выполнения цикла G C - скорее всего, нет. Ignorable? Я бы сказал полностью. В конце концов, что вас волнует из GC - то, что требуется много времени, чтобы освободить много места, предпочтительно с супер крошечными событиями остановки мира.

Давайте поговорим о потенциальных накладных расходах в G C основные две фазы: маркировка и эвакуация / переоткрытие (Шенандоа / ЗГ C). Первая mark фаза, где GC выясняет, что такое мусор (фактически идентифицируя то, что живо).

Если объекты, созданные внутренними объектами Stream, недоступны, они никогда не будут сканироваться (здесь нет нулевых накладных расходов), и если они достижимы, сканирование будет очень быстрым. Другая сторона истории: когда вы создаете объект и GC может коснуться его , в то время как работает в фазе отметки, медленный путь LoadBarrier (в случае Shenandoah) будет активный. Это добавит несколько десятков ns я предполагаю к общему времени этой конкретной фазы GC, а также некоторое пространство в очередях SATB. Алексей Шипилев в одном из выступлений сказал, что он пытался измерить накладные расходы от выполнения одного барьера и не мог, поэтому он измерил 3, а время было в районе десятков ns. Я не знаю точных деталей ZG C, но там также есть LoadBarrier.

Суть в том, что эта фаза пометки выполняется одновременно, когда приложение работает, так что ваше приложение все равно будет работать отлично. И даже если какой-то код G C будет запущен для выполнения какой-либо конкретной операции c (Load Barrier), он будет чрезвычайно быстрым и полностью прозрачным для вас.

Второй этап - «сжатие», или освобождая место для будущих ассигнований. Что делает G C, так это перемещает живые объекты из регионов с наибольшим количеством мусора (наверняка, Shenandoah) в пустые регионы. Но только живые объекты. Таким образом, если в определенном регионе есть 100 объектов и только 1 жив, только 1 будет перемещен, тогда весь этот регион будет помечен как свободный. Таким образом, потенциально, если реализация Stream генерирует только мусор (то есть: в данный момент не существует), это «бесплатный обед» для G C, он даже не узнает о его существовании.

Лучшей картиной здесь является то, что этот этап все еще выполняется одновременно. Чтобы сохранить «параллелизм» активным, вам нужно знать, сколько было выделено от начала до конца цикла G C. Эта сумма является минимальным «дополнительным» пространством, которое вам нужно иметь в верхней части процесса java, чтобы G C был счастлив.

Итак, в целом вы смотрите на супер крошечный эффект ; если есть вообще.

...