(java || kotlin) && devOps
369 subscribers
6 photos
1 video
6 files
306 links
Полезное про Java и Kotlin - фреймворки, паттерны, тесты, тонкости JVM. Немного архитектуры. И DevOps, куда без него
Download Telegram
Всем привет!

Нашел отличное видео по исключениям в Java https://www.youtube.com/watch?v=UIbbNsta2UE

Краткий конспект, не влияющий на рекомендацию посмотреть видео:
1) затраты на выбрасывание исключений конечно же есть, но если исключение в вашем сервисе равно ошибке, то проблем с производительностью не будет. Т.к. ошибки как правило не выбрасываются сотнями и тысячами в секунду
2) если ваши исключение выбрасывается в строго определенном месте кода - можно убрать из него stack trace, это неплохо так увеличит производительность. На самом деле если просто не обращаться к stack trace, то она уже увеличится, но для надежности лучше вообще не прикреплять stack trace к исключению. Или использовать StackWalking API https://www.baeldung.com/java-9-stackwalking-api
3) самый спорный и опасный совет для того же кейса - исключение, выбрасываемое в одном месте - закэшировать исключение, так его выброс будет еще быстрее. Но по сути это старый добрый go to. Использовать с осторожностью!)
4) исключение должно содержать весь контекст ошибки, в идеале с предложениями по ее исправлению. Чтобы структурировать информацию об ошибке есть библиотека https://github.com/melix/jdoctor Активность в репозитории слабенькая, но сама идея мне нравится.
5) как известно, есть исключения, которые не стоит ловить - например, OutOfMemory и StackOverflow. Но если очень надо, то OutOfMemory все же можно) Главное - заранее создать все необходимые для сохранения информации о проблеме объекты, ведь после появления OutOfMemory памяти уже не будет.

А еще из интересного - после просмотра видео станет понятно, как работает SneakyThrows в Lombok

#java #exceptions
Всем привет!

Продолжаю серию полезных видео - https://youtu.be/j-i3NQiKbcc
Тут по полочкам расписывает как работает логирование в Java.

Краткий конспект по архитектуре логирования:
1) адаптер - предоставляет API, которое вызывается из кода. На данный момент их 3 - SL4J, JCL (Apache Common Logging) и JBoss Logging. Самый распространенный и рекомендуемый - SLF4J
2) bridge - нужен, когда какая-то библиотека использует не тот адаптер, что мы хотим. По сути адаптер на адаптер, который эмулирует API, вызываемое из кода, и пробрасывает вызовы в нужный адаптер, как правило slf4j. Понятно, что когда у нас есть адаптер на адаптер, есть риск бесконечной рекурсии. Про это надо помнить)
3) движок логгера - компонента, которая пишет логи. Примеры: log4j, log4j2, logback, JUL\JDK (встроенный в JDK)
4) appender - компонент, определяющий физическое место, куда пишутся логи: консоль, диск, БД, MQ... Вот полный список для log4j2 https://logging.apache.org/log4j/2.x/manual/appenders.html
5) фильтры и конверторы - позволяют отфильтровать или преобразовать сообщения на клиенте

Плюс 3 хороших совета из видео:
1) соблюдать гигиену classpath - чистить его от лишних библиотек
2) логи в теории могут стать основой мониторинга, когда мы отбрасываем специальным образом размеченную запись в лог, которая после обработки лога становится событием мониторинга
3) не добавлять как зависимость в свои библиотеки движок логгера. Пусть его выберет потребитель, а не разбирается с вашими транзитивными зависимостями

И 2 полезные утилиты - миграторы на logback и slf4j с альтернативных библиотек логирования.

Из минусов вижу пожалуй один - там идет рассказ о связке slf4j и logback. Если во время создания видео logback сильно обогнал log4j, то сейчас с log4j2 ситуация меняется. Неплохо бы добавить сравнение с log4j2.

#java #logging
Всем привет!

Какие компиляторы есть в Java? Сколько их вообще?
Простой ответ - один, называется javac. Им мы компилируем исходники в байт-код, который потом исполняет JVM.
Исполняет и что важно оптимизирует.
Вообще говоря, основные оптимизации происходят именно runtime, а javac является довольно простым.
Идея в том, что собирается статистика использования кода во время выполнения, часто используемый код компилируется в "нативный" - ассемблер для конкретного процессора, а неиспользуемый - удаляется. Таким образом получаем плюс еще один компилятор - JIT, он же Just in Time. Только на самом деле, исторически, компиляторов два - один быстрый, но оптимизирующий не оптимально))), второй - наоборот, медленный и хорошо оптимизирующий. C1 и C2, сейчас они используются в паре, подробнее можно почитать тут https://for-each.dev/lessons/b/-jvm-tiered-compilation

А можно без байт-кода? Да, есть AOT - Ahead of Time компилятор, называется native-image, поставляется в GraalVM https://www.graalvm.org/latest/reference-manual/native-image/
Он сразу компилирует в требуемый "нативный" код.
А если поддержки требуемой процессорной архитектуры нет? Был момент доминирования x86, но сейчас растет популярность ARM архитектур, а там, я так понимаю, тот еще зоопарк.
А для этого уже существует промежуточный язык и набор компиляторов LLVM https://llvm.org/. Что-то типа Java байт-кода, только не привязанный к Java. GraalVM его тоже поддерживает https://www.graalvm.org/latest/reference-manual/native-image/LLVMBackend/
А можно его использовать как runtime компилятор? Почему нет, в Azul JDK решили отказаться от C1\C2 и сделать свой компилятор с блекджеком и LLVM - https://www.azul.com/products/components/falcon-jit-compiler/ Да, ошибся немного, блекджека там, увы, нет)

А еще есть компиляторы Kotlin, Scala, Groovy, Jython, JRuby... И Kotlin native, также использующий LLVM https://kotlinlang.org/docs/native-overview.html В общем я сбился со счета)

#java #jvm #jdk #native_image #compilers
Всем привет!

Продолжу серию постов https://t.me/javaKotlinDevOps/269 про оптимизацию производительности Java приложения.
В первых двух частях я говорил про такие технологии как:
1) native image - компиляция в нативный код на этапе сборки, т.об. устраняется необходимость class loading-а и JIT компиляции
2) CRaC - сохраняет и восстанавливает состояние работающего Docker образа с JRE на диск, т.об. мы получаем уже оптимизированный код

Какие еще могут быть способы выйти на оптимальную производительность побыстрее? native image мы пока отбрасываем, у нас обычная JVM и на ней запускается байт-код.
Встречный вопрос - а что мешает достижению оптимальной производительности? Как ни странно - JIT компилятор. Ведь чтобы ему понять, как оптимизировать байт-код, нужно собрать статистику. Причем процесс сбора статистики может быть цикличным - собрали, оптимизировали, поняли что оптимизация неверная, вернули байт-код обратно... И это все требует времени. А почему бы тогда не собрать статистику по использованию кода заранее, прихранить ее куда-нибудь, а потом использовать сразу со старта.
Эта техника называется Profile-Guided Optimization, в нее умеет GraalVM https://www.graalvm.org/latest/reference-manual/native-image/optimizations-and-performance/PGO/basic-usage/ и упоминаемая ранее Azul JDK https://docs.azul.com/prime/Use-ReadyNow Но к сожалению оба - только в коммерческой версии.
Еще похожую технику использует стандартная OpenJDK при tired compilation https://for-each.dev/lessons/b/-jvm-tiered-compilation но в данном случае речь идет про отпимизацию в течение одной рабочей сессии.

P.S. Это еще не все возможные варианты, не переключайтесь)

P.P.S. Может возникнуть вопрос - зачем GraalVM использует профилирование, он же и так все оптимизировал? Нет, не все. На этапе компиляции нет информации об реальном использовании кода. А оптимизация - это не только компиляция в нативный код, это еще может быть выбрасывание лишних проверок, разворачивание цикла и т.д.

#jre #performance #java_start_boost