Первое что стоит отметить, когда работаешь с Native Image цикл доставки меняется. У нас есть код в хранилище (repository) и следующий результат - контейнер с запечённым бинарником в Системе Артефактов. Внутрь бинарника уже не залезть (плюс векторы атак меньше на бинарник). Поэтому часть проверок (SAST и т.д.) должны уехать на коммиты/PR, а это в свою очередь распараллеливание процессов. И уже по факту надо будет смотреть, что с показателем TTM произойдёт.
Наверно, потребление памяти действительно не проблема, если стоимость оборудования оплачивается не из личного кармана, а из чужого. Если у бизнеса есть возможность оплачивать железо, требования к сервису позволяют использовать медленный старт приложения, latency больше нескольких секунд - да с лёгкостью можно отказаться от Native.
А вот с Project Valhalla нужно очень чётко понимать разницу с Native: это разные уровни. Когда мы говорим про Native Image (GraalVM), то мы говорим об инфраструктурном уровне, который борется с оверхедом самой платформы (JVM). Project Valhalla - это архитектурный уровень, который борется с оверхедом модели данных. Никто не запрещает использовать одновременно Native Image и Project Valhalla. Более того, они будут давать следующий эволюционный скачок в развитии Java.
Тут важно не путать процесс и результат. AOT - это компилятор, способ сборки. У него задача - запечь код. У него работа закончилась, когда он собрал бинарник. Native Image - это бинарник. При работе бинарника динамическая компиляция кода не происходит. Более того, появляется эффект при работе с памятью - меньше фрагментация и данные более скомпоновано лежат (Data Locality), что в свою очередь уже как раз даёт эффект при работе с данными (Data Prefetching).
С моей зарплатой в виде мерча (футболки и носков) из меня так себе продавец. Если по существу: укажите, где именно в статье вы увидели претензию на авторство GraalVM? Исследование как раз про разницу в производительности готовых решений Axiom JRE и Axiom NIK. Всё указанное, что я проделал - вы можете успешно повторить. В репозитории лежат скрипты сборки контейнеров, которые собирают образы на базе бесплатных образов из Docker Hub.
@faxenoff, @pkokoshnikov, @broondulyak, спасибо за дискуссию! Действительно, у Java изначальная философия была один раз код напиши и запускай на разных платформах.
В современных реалиях - собери один раз в контейнер, запускай контейнер.
Если речь про другой стек (например: JavaFX, Java Swing; где пользователи работают с окнами) и необходимо охватить пользователей разных ОС, то здесь Native Image действительно понадобиться собирать под каждую ОС отдельно.
Вообще, есть смысл в новых работах уделить внимание CI/CD. Пометил себе.
@Dhwtj, всё верно! Справедливо указали "налог на сборку" и возможную просадку производительности в сравнении с прогретымJIT!
В следующих работах постараюсь включить исследования, связанные с PGO (Profile-Guided Optimization) и использование современных версий GraalVM. PGO позволит догнать производительность с 80% (в среднем при компиляции) до 100% (на 10-20%), а современные версии GraalVM должны компилировать код гораздо быстрее.
Дополню, что помимо микросервисов, самые идеальные задачи для GraalVM - это задачи, когда нужно запустить приложение, выполнить приложение, завершить приложение (консольные утилиты, утилиты с графическим интерфейсом).
@BugM, @Dhwtj, спасибо за глубокие замечания! Согласен, "Детские болезни" Native Image с рефлексией и JNI в эпоху Spring Boot 2 часто превращали разработку в квест по написанию конфигов. А вообще, здесь напрашивается детальный разбор: Spring Boot 2 vs Spring Boot 3 (+ зацепить Spring Boot 4) в Native-режиме, как встроенный AOT-движок в SB3 (+SB4) реально решает проблемы с метаданными, сравнение производительности так же JVM VS Native-режим. Постараюсь подготовить материалы на эту тему.
В данной статье была цель предоставить варианты оптимизации кода, в том числе и Правило №7. BigDecimal vs Long (Битва за примитивы).
Действительно, если проект находится на этапе реализации, то смело используйте BigDecimal. Выше указали основные аргументы почему стоит использовать BigDecimal и какие вопросы он решает + накину свои:
Проблема деления (Scale Up)
Проблема переполнения (Overflow)
Сложность поддержки. Необходим дополнительный контроль в большой команде с разной экспертизой. Банальная проблема - есть риск забыть привести данные к нужному формату
Стандартное бизнес-приложение, много операций делений/процентов
По результатам нагрузочного тестирования можно будет сформировать понимание - необходимо ли производить оптимизации.
Когда стоит сразу задуматься об использовании денежных значений в минимальных единицах (long / int):
High-load
Критичен бюджет аллокаций (жёсткий лимит ресурсов)
@remindscope отличная точка для дискуссии! Если вопрос в написании нового решения в 2026 году, есть эксперты в команде по Go - почему бы и не написать на языке Go? Да конечно можно! И с философией Java так же правы - пиши один код и запускай везде!
GraalVM - это не сова, это вынужденная адаптация Java под современные реалии облаков (Cloud Native). В данном случае Java просто эволюционирует, чтобы не проиграть Go или Rust в нише маленьких контейнеров. При этом концепция запуска бинарника под каждую платформу также сохраняется, но с некоторой "эволюцией" - запуск внутри контейнера.
Контейнеризация заставляет и главное, что позволяет большинству технологий прогрессировать и меняться в лучшую сторону.
@kmatveev,
Поделитесь своим опытом фиксирования пауз GC в GraalVM. Какие инструменты использовали? Какую проблему решали?
@kmatveev, я очень рад, что статья и комментарии смогли привлечь ваше внимание и зацепить.
@scherlock, @Siemargl, спасибо за дискуссию! Перечитывал и обдумывал с чего начать.
@scherlock,
Первое что стоит отметить, когда работаешь с Native Image цикл доставки меняется. У нас есть код в хранилище (repository) и следующий результат - контейнер с запечённым бинарником в Системе Артефактов. Внутрь бинарника уже не залезть (плюс векторы атак меньше на бинарник). Поэтому часть проверок (SAST и т.д.) должны уехать на коммиты/PR, а это в свою очередь распараллеливание процессов. И уже по факту надо будет смотреть, что с показателем TTM произойдёт.
Наверно, потребление памяти действительно не проблема, если стоимость оборудования оплачивается не из личного кармана, а из чужого. Если у бизнеса есть возможность оплачивать железо, требования к сервису позволяют использовать медленный старт приложения, latency больше нескольких секунд - да с лёгкостью можно отказаться от Native.
А вот с Project Valhalla нужно очень чётко понимать разницу с Native:
это разные уровни. Когда мы говорим про Native Image (GraalVM), то мы говорим об инфраструктурном уровне, который борется с оверхедом самой платформы (JVM). Project Valhalla - это архитектурный уровень, который борется с оверхедом модели данных.
Никто не запрещает использовать одновременно Native Image и Project Valhalla. Более того, они будут давать следующий эволюционный скачок в развитии Java.
@Siemargl,
Тут важно не путать процесс и результат.
AOT - это компилятор, способ сборки. У него задача - запечь код. У него работа закончилась, когда он собрал бинарник. Native Image - это бинарник. При работе бинарника динамическая компиляция кода не происходит.
Более того, появляется эффект при работе с памятью - меньше фрагментация и данные более скомпоновано лежат (Data Locality), что в свою очередь уже как раз даёт эффект при работе с данными (Data Prefetching).
Отметил себе раскрыть эти темы в будущих статьях.
С моей зарплатой в виде мерча (футболки и носков) из меня так себе продавец.
Если по существу: укажите, где именно в статье вы увидели претензию на авторство GraalVM?
Исследование как раз про разницу в производительности готовых решений Axiom JRE и Axiom NIK.
Всё указанное, что я проделал - вы можете успешно повторить. В репозитории лежат скрипты сборки контейнеров, которые собирают образы на базе бесплатных образов из Docker Hub.
@ris58h,
Я допустил ошибку в блоке. Спасибо за замечание!
Слышу критику. Меняюсь.
Вам и всем остальным неравнодушным +!
@pkokoshnikov, справедливо заметили, что важная часть работы Native Image в части CPU не была задокументирована.
Текущую статью дополнил материалами. Но это самый минимум в данной статье, который я смог сделать с тем материалом, который был собран.
В будущих работах уделю внимание производительности и показателям утилизации CPU, методике нагрузочного тестирования. Отметил себе.
@faxenoff, @pkokoshnikov, @broondulyak, спасибо за дискуссию!
Действительно, у Java изначальная философия была один раз код напиши и запускай на разных платформах.
В современных реалиях - собери один раз в контейнер, запускай контейнер.
Если речь про другой стек (например: JavaFX, Java Swing; где пользователи работают с окнами) и необходимо охватить пользователей разных ОС, то здесь Native Image действительно понадобиться собирать под каждую ОС отдельно.
Вообще, есть смысл в новых работах уделить внимание CI/CD. Пометил себе.
@Dhwtj, всё верно! Справедливо указали "налог на сборку" и возможную просадку производительности в сравнении с прогретым JIT!
В следующих работах постараюсь включить исследования, связанные с PGO (Profile-Guided Optimization) и использование современных версий GraalVM. PGO позволит догнать производительность с 80% (в среднем при компиляции) до 100% (на 10-20%), а современные версии GraalVM должны компилировать код гораздо быстрее.
Дополню, что помимо микросервисов, самые идеальные задачи для GraalVM - это задачи, когда нужно запустить приложение, выполнить приложение, завершить приложение (консольные утилиты, утилиты с графическим интерфейсом).
@kmatveev, справедливое замечание по поводу дискретности мониторинга!
Действительно, Prometheus/Grafana с дефолтным шагом скрейпинга может не увидеть паузы в 1-5 мс.
В новых сравнениях/работах добавлю анализ работы через JFR и прямой профайлинг GC logs. Должны буду видны микро паузы, которые спрятались.
@BugM, @Dhwtj, спасибо за глубокие замечания!
Согласен, "Детские болезни" Native Image с рефлексией и JNI в эпоху Spring Boot 2 часто превращали разработку в квест по написанию конфигов.
А вообще, здесь напрашивается детальный разбор: Spring Boot 2 vs Spring Boot 3 (+ зацепить Spring Boot 4) в Native-режиме, как встроенный AOT-движок в SB3 (+SB4) реально решает проблемы с метаданными, сравнение производительности так же JVM VS Native-режим.
Постараюсь подготовить материалы на эту тему.
@ruslan_astratov спасибо за обратную связь!
Какие варианты оптимизации открыли для себя?
Удалось применить их в деле?
@alexander_pesh , @Pdasilem , @Siemargl , @GreyN , спасибо за дискуссию!
В данной статье была цель предоставить варианты оптимизации кода, в том числе и Правило №7. BigDecimal vs Long (Битва за примитивы).
Действительно, если проект находится на этапе реализации, то смело используйте BigDecimal. Выше указали основные аргументы почему стоит использовать BigDecimal и какие вопросы он решает + накину свои:
Проблема деления (Scale Up)
Проблема переполнения (Overflow)
Сложность поддержки. Необходим дополнительный контроль в большой команде с разной экспертизой. Банальная проблема - есть риск забыть привести данные к нужному формату
Стандартное бизнес-приложение, много операций делений/процентов
По результатам нагрузочного тестирования можно будет сформировать понимание - необходимо ли производить оптимизации.
Когда стоит сразу задуматься об использовании денежных значений в минимальных единицах (long / int):
High-load
Критичен бюджет аллокаций (жёсткий лимит ресурсов)
Пишите ядро торгового движка/блокчейна
@remindscope отличная точка для дискуссии!
Если вопрос в написании нового решения в 2026 году, есть эксперты в команде по Go - почему бы и не написать на языке Go? Да конечно можно!
И с философией Java так же правы - пиши один код и запускай везде!
GraalVM - это не сова, это вынужденная адаптация Java под современные реалии облаков (Cloud Native). В данном случае Java просто эволюционирует, чтобы не проиграть Go или Rust в нише маленьких контейнеров. При этом концепция запуска бинарника под каждую платформу также сохраняется, но с некоторой "эволюцией" - запуск внутри контейнера.
Контейнеризация заставляет и главное, что позволяет большинству технологий прогрессировать и меняться в лучшую сторону.
@yrub, снимаю шляпу! Про SSA-форму - в точку!
Внёс уточнение в статью, чтобы не плодить мифы.