Pull to refresh
55
0
Андрей Лыгин @alygin

Оператор ЭВМ

Send message
Всплыло в рамках расследования фактов инсайдерской торговли на той же самой информации, но только со стороны менеджера уже самой Илиады.
1. Еще никого не оштрафовали, это пока только представитель следствия рекомендует оштрафовать.
2. Обоснование — незаконное распространение инсайдерской информации. А вовсе не за то, что кто-то там дальше на основе этой информации сделал предложение. Залуски, получив доступ к этой информации, не имел права никому ее сообщать. Он сообщил своему коллеге, а тот и дальше по компании растрепал, очевидно.

В соответствии с регуляциями MAR, эта информация, а) действительно, является инсайдерской, б) была получена Залуски не по обычным каналам в рамках выполнения им своих должностных обязанностей и передача ее другим лицам является незаконной.
Да, самого совесть грызет, но времени на хабростатьи пока что катастрофически не хватает. Но, конечно, нужно продолжить, тем более, что с момента этой публикации были интересные подвижки в мире GC для JVM.

Пойду пока хотя бы новые картинки придумаю для продолжения, глядишь и сдвинется дело :)
Да, наверняка речь про них. Хотя все основные игроки утверждают, что влияние патчей на производительность практически не заметно для большинства пользователей, но призывают проверять это на своих нагрузках самостоятельно. Как это все сказывается на энергопотреблении, не говорят.
Intel заявила (без подробностей), что нашла способ устранения обеих уязвимостей (и Meltdown и Spectre). Обновления уже, якобы, выпущены для большинства процессоров моложе пяти лет. Судя по всему, лечат комбинацией патчей ОС и прошивок процессоров.
а что делать, если у нас из старого поколения есть ссылка на объект из молодого?
получается, что даже при малой сборке надо скопировать в чистую часть сурвайвора все объекты, на которые ссылалось старшее поколение


Все так, как раз такой пример со ссылкой из старшего поколения в младшее есть в первой части.

Ссылки из старых объектов на короткоживующие объекты — это не очень хорошо и может увеличивать количество полных сборок. Но при этом перекидывание объекта между survivor'ами прежде чем переместить его в старшее поколение, защищает от таких ситуаций. Ссылка из старшего поколения в младшее должна продержаться достаточно долго и пережить несколько малых циклов сборки, чтобы это привело к «затягиванию» старым объектом молодого в Tenured. А раз она прожила так долго, то и объект уже сложно назвать короткоживущим.

Если все же нежелательные объекты просачиваются в старшее поколение и на уровне кода с этим ничего поделать не удается, можно попробовать увеличить значения InitialTenuringThreshold и MaxTenuringThreshold, заставив объекты созревать в survivor'ах дольше, прежде чем отправиться в tenured. Но все это, конечно, следует делать очень аккуратно, так как увеличение порога созревания приведет к тому, что в survivor'ах будет больше объектов, возможна нехватка места и преждевременное выдавливание объектов в tenured (еще одна причина попадания молодых объектов в старшее поколение), так что может потребоваться и донастройка размеров областей.
В кратком введении в Java Memory Model, возможно, стоило бы упомянуть о том, какие темы она покрывает, а к каким совсем никак не относится. Очень часто приходится видеть, что люди под видом JMM ожидают (как в комментариях выше) или даже преподносят что-то, что не имеет к ней никакого отношения: как устроены объекты в памяти, как они размещаются в куче, как работают сборщики мусора и прочее, что относится к управлению памяти, но не к модели. В результате возникает либо разочарование от того, что рассказали не то (если читатель ее неправильно понимает), либо некорректное представление о сути JMM начинает распространяться сильнее (если сам автор неправильно ее понимает и преподносит).
Практически ничего из того, что вы упомянули, не относится к Java Memory Model. JMM — это про организацию взаимодействия потоков через общую память, про допустимые в языке пути исполнения инструкций. Расположение объектов в памяти, куча, стеки и сборщики мусора и OutOfMemory, это не JMM.
в системе должно быть 0 (ноль) ошибок на 560 000 строк кода. И работать она должна несмотря ни на какие сбои и неполадки железа и софта, ошибки персонала.

Стандартное в наши дни требование практически от любого заказчика в корпоративном сегменте :)

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

? Используете похожие на NASA'вские правила при разработке? Требуете как и они от заказчика подробнейшие спецификации? Содержите ли сильнейший отдел тестировщиков? Пытаетесь вытягивать на личных профессиональных качествах старших разработчиков?
Вспомнилась интересная (даже спустя 20 лет после написания) статья о том, как устроена работа в одной из групп, разрабатывающей ПО для бортовых систем шаттлов: They Write The Right Stuff. В числе прочего, в ней есть интересные данные по доле ошибок в расчете на количество строк кода, по объему и качеству спецификаций в проекте, а также по размеру его бюджета. Пара цитат, передающих общую идею:

«Our requirements are almost pseudo-code,» says William R. Pruett, who manages the software project for NASA. «They say, you must do exactly this, do it exactly this way, given this condition and this circumstance.»

The group has one customer, a smart one. And money is not the critical constraint.

Ничуть не принижая способности их разработчиков, следует отметить, что с организационной точки зрения условия им созданы очень близкие к идеальным.
Вы почему-то продолжаете адресовывать претензии по выбору исходных именований сборщиков именно мне. Не я выбирал термины Parallel и Concurrent для них. Вам они могут не нравиться, и вы можете настаивать на их переименовании. Но логичнее это делать не здесь, а на форуме Oracle.

Я же объяснил логику, скрытую за этими терминами, и выбрал для них соответствующие этой логике переводы. Если вы сомневаетесь, что я правильно понял, что имелось в виду под терминами «parallel» и «concurrent» в именах сборщиков, то приглашаю вас почитать официальную документацию Oracle, обращая внимание на использование этих терминов. Они используются ровно так, ровно в том виде и ровно в том значении, что я описал.

И никаких реальных, более корректных альтернатив вы опять не предлагаете. Честно говоря, не вижу смысла продолжать диалог в таком русле.

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

Попробуйте взглянуть на мир не глазами разработчика, не глазами приложения, а глазами сборщика. Он бодрствует только во время выполнения своих обязанностей, а остальное время спит и ничего не видит. Как же выглядит видимая ему жизнь?

Сборщик просыпается, видит кучу мусора и не торопясь, в одном потоке, его собирает, после чего засыпает. Как его назовем? Пусть будет Serial GC, ведь всё последовательно и нужно с чего-то начать.

Проходят годы, появляется второй тип сборщика. Он просыпается, видит кучу мусора и разбирает ее, но уже используя несколько потоков, работающих параллельно. Как назовем такой сборщик? Логично назвать Parallel GC, нет?

Предыдущий сборщик работает быстро, но даже его короткие паузы устраивают не все приложения, и появляется новый тип сборщика, который во время некоторых фаз своего бодрствования обнаруживает, что, оказывается, кроме него есть еще и другие потоки (приложения), с которыми ему приходится работать в конкурентом режиме. Что это за фазы такие? Это фазы Mark и Sweep. Как назовем такой сборщик, у которого фазы Mark и Sweep проходят в конкурентном режиме? Не самым плохим вариантом будет Concurrent Mark Sweep. Длинно. Сократим до CMS.

Годы идут, объемы данных растут, требования к задержкам ужесточаются, но и эволюция не стоит на месте. Появляется сборщик, который, помимо того, что имеет конкурентные фазы, еще и может выбирать, какую часть вверенного ему пространства памяти убирать, а какую оставить на потом. И он, как мудрый сборщик, решает в первую очередь убирать то, что больше всего замусорено. Как назовем такой сборщик? Давайте Garbage First, вроде не самый плохой вариант. Но тоже длинно, сократим до GF? Нее, все будут смеяться, что это girlfriend. Над G1 так не посмеешься, да и выглядит современнее, остановимся на этом варианте.

Два последних сборщика, в отличие от первых, имеют фазы конкурентного выполнения. Как бы их назвать собирательно? Конкурентные. Не потому что они так всегда взаимодействуют с основным приложением. А потому что у них есть конкурентные фазы, а у других нет, считаете не логично? Вы ведь протягивая 50 рублей продавщице мороженого и говоря «мне ореховое» не ожидаете (надеюсь), что она вам большой орех на палочке даст. И правильно, она вам его не даст, а даст мороженое с кусочками орехов.

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

А предложение перевести Parallel GC как «многопоточный останавливающий» с одновременным упреком в путанице и в отсутствии логики в исходных названиях вряд ли можно рассматривать всерьез. Останавливают выполнение потоков приложения все (все!) сборщики, поэтому и раздел «Ситуации STW» есть в описании каждого из них. Многопоточными являются три из четырех. «Однопоточный останавливающий», «многопоточный останавливающий без конкурентного выполнения», «многопоточный останавливающий с конкурентным выполнением фаз Mark и Sweep», «многопоточный останавливающий с конкурентными фазами и дробными поколениями». Так будет звучать ваше предложение о переводе терминов Serial / Parallel / CMS / G1 полностью?

А с таким подходом к выискиванию несоответствий вы можете бесконечно спорить с кем угодно и о чем угодно. Начать можно вообще с самого термина «garbage collector». Собиратель? Коллекционер? Коллектор? Да мы вообще мусор никуда не собираем и не коллекционируем, мы его просто удаляем, поэтому давайте не будем запутывать картину: garbage deleter! Ах да, если уж разбираться всерьез, то на самом деле мы его даже не удаляем, а просто оставляем где был и игнорируем. Может, garbage ignorer?

И так вы можете до бесконечности. А я, пожалуй, воздержусь до появления реальных, полностью продуманных предложений.
ОК, давайте разберем еще раз всё подробно. Выше в комментариях приведена ссылка на статью Concurrent != Parallel, в которой как раз объясняется разница между терминами «параллельный» и «конкурентный», и содержится призыв не путать эти понятия. Вот основная идея: Параллельный — это реально выполняющийся параллельно, без конкуренции за какие-либо ресурсы, приводящей к необходимости приостановок выполнения. Пример параллельного выполнения — N потоков на N ядрах процессора без общей памяти. Конкурентный — это выполняемый как-бы параллельно, но из-за конкуренции за ресурсы на самом деле никакого реального параллельного выполнения нет. Пример конкурентного выполнения — два потока на одном ядре процессора, или N потоков, пишущих в одну и ту же область памяти.

Теперь давайте взглянем на наши сборщики, в которых два этих понятия используются абсолютно правильно:

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

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

То есть использование названия concurrent и его перевода как «конкурентный» оправдано для CMS/G1 и не может иметь отношения к Parallel GC. При этом использование названия parallel и его перевода как «параллельный» абсолютно оправдано для Parallel GC и не может относиться с CMS/G1.

В свете вышесказанного считаю, что «конкурентный» подходит больше, чем «одновременный».

SMM — Social Media Marketing.
Да, конечно, моя ошибка. Спасибо.
Малая сборка — это всегда STW, независимо от сборщика. Она останавливает все потоки приложения, так что с этой точки зрения наличие у вас синхронизации никак не влияет на паузы. Я не знаю, на каком этапе работы вашего приложения была выполнена указанная выше сборка, но если в вашем приложении есть постоянные данные, которые к этому моменту уже были полностью начитаны, то вам можно попробовать явно задать большое значение для размера младшего поколения. В вашем случае видно, что в старшем поколении после сборки осталось чуть меньше 700 МБ. Возможно, это и есть ваши постоянные данные и больше их не будет. Если так, то можете попробовать установить -XX:MaxNewSize=5400m, чтобы явно отдать почти все место, не занятое постоянными данными, под младшее поколение. А если ваше приложение обрабатывает множество относительно небольших запросов, и вы хотели бы уменьшить время отклика на них, то, возможно, 6ГБ для него слишком много. Чем больше куча, тем дольше она чистится, часто уменьшение кучи приводит к положительным результатам в транзакционных приложениях. Попробуйте в этом случае уменьшить Xms и Xmx, одновременно уменьшив указанное выше значение MaxNewSize на такую же величину.

Но имейте в виду, что тут может быть очень много нюансов. Возможно, в указанной сборке учитываются не все постоянные объекты. Возможно, у вас есть долгоиграющие методы, которым нужен такой большой объем памяти, поэтому его нельзя уменьшать. Возможно, у вас периодически создаются большие объекты (больше нескольких мегабайт), которые приходится размещать в Tenured, минуя Eden. И еще много чего может сыграть свою роль. Тут в комментарии я все не смогу перечислить подробно. Постараюсь как можно больше описать в следующей статье.
Да, малые сборки во всех сборщиках, включая G1, выполняются при остановленных потоках основного приложения. Ответьте, пожалуйста, про версию JRE. Если это 7-ка, как я предположил, то G1 в ней может быть еще достаточно сырым. В 8-й версии он заметно лучше.
Хотя это больше похоже на Parallel GC, чем на G1. Какую версию JRE вы используете?
Я правильно понял, что это 7-я джава?
Сборку нужно в динамике наблюдать. По одному этому примеру видно только, что в старшем поколении у вас, действительно, очень много мусорных данных (освобождено ~1.5 ГБ за сборку, из которых больше гигабайта из старшего поколения). Если вы такую же картину наблюдаете во всех сборках, то нужно перенастраивать распределение кучи между младшим и старшим поколениями. Хотя по этому отрывку лога видно, что G1 уже сам начал это делать, увеличив размер младшего поколения. Скорее всего, следующая сборка будет уже лучше. Как я сказал, нужно в динамике наблюдать и дать время сборщику подстроиться под ваше приложение.
Нестабильность времени отклика обычно возрастает когда слишком часто выполняются полные (в случае G1 смешанные) сборки. Возможно, у вас слишком много мусорных данных просачивается в старшее поколение. Либо возникают evacuation fault'ы. И то и другое грубо можно проверить хотя бы с помощью -verbose:gc. И на загрузку ядер посмотреть. Если они полностью загружены самим приложением, то конкурентные сборщики (CMS и G1) могут терять эффективность. Я в следующей статье-двух планирую описать множество различных аспектов, влияющих на поведение сборщиков, с примерами настройки. Надеюсь, вам удастся найти там полезные идеи для оптимизации сборки в вашем приложении, потому что G1 все-таки обычно обеспечивает лучшее время отклика, если в приложении нет какой-нибудь серьезной специфики. А пропускную способность он, действительно, просаживает, таков его принцип работы.
А какой объем кучи? И сколько ядер процессора было доступно приложению?

Information

Rating
Does not participate
Location
Москва, Москва и Московская обл., Россия
Registered
Activity