Бенчмаркінг різних JVM та багато графіків
Привіт, спільното! Нещодавно при розробці нового проєкту переді мною повстало питання вибору JVM. На сьогодні є великий вибір як повністю опенсорсних, так і пропрієтарних реалізацій та дистрибуцій, тож мені стало цікаво перевірити, чим вони відрізняються окрім ліцензій та технічної підтримки від вендорів. Результатами тестів вирішив поділитись і з вами. Для порівняння відібрано 10 найпопулярніших дистрибуцій JDK для 17 версії Java. А саме:
- Amazon Corretto — Опенсорсний дистрибутив JDK від компанії Amazon, розповсюджується по ліцензії GPLv2 with CPE.
- Alibaba Dragonwell — Дистрибутив від китайської компанії Alibaba, розповсюджується по такій самій ліцензії.
- GraalVM CE — Модульний рантайм з підтримкою різних мов програмування. Основний модуль, що реалізує JDK, поставляється по ліцензії GPLv2 with CPE.
- GraalVM EE — Пропрієтарне видання GraalVM. Ліцензія дозволяє безоплатне використання в особистих цілях.
- Java SE (Oracle JDK) — Пропрієтарна JDK від Oracle. Розповсюджується під ліцензією Oracle No-Fee Terms and Conditions License.
- Liberica JDK — Опенсорсна дистрибуція JDK від компанії BellSoft.
- OpenJ9 — Альтернативна опенсорсна JDK від компанії Eclipse. На відміну від інших JDK з цього списку використовує повністю власну реалізацію JVM замість HotSpot. Розробники обіцяють на 42% швидший запуск порівняно з JVM на базі HotSpot.
- OpenJDK — Класична опенсорсна JDK, що лежить в основі більшості JDK з цього списку. Розповсюджується по ліцензії GPLv2 with CPE.
- Temurin (Adoptium) — Ще одна опенсорсна дистрибуція JDK від компанії Eclipse, на цей раз на базі OpenJDK зі звичайним HotSpot. Як і інші опенсорсні дистрибутиви, має ліцензію GPLv2 with CPE.
- Zulu — Опенсорсна дистрибуція JDK від компанії Azul.
Для тестування я написав простенький бенчмарк, який тестує всі основні важливі для мого проєкту аспекти продуктивності JVM, окрім, хіба що, GC. Сам бенчмарк тестувався тільки на
В рамках цього тесту бенчмарк виконував по 3 запуски JVM з метою зібрати середню статистику поміж запусками та знизити вплив зовнішніх факторів на результати. Також у деяких тестах бенчмерк проводить по 5 викликів тестового метода, аби проаналізувати вплив JIT-оптимізацій на результат.
Дисклеймер
Ця стаття — моє особисте мінідослідження, тому наведені тести покривають далеко не весь функціонал JVM. Також хочу зазначити, що числові показники у графіках та результатах бенчмарку слід використовувати лише для порівняння між собою результатів тестів, виконаних в однакових умовах і на однаковому залізі. Більшість наведених показників затримок трохи завищені через оверхед від бенчмарку.
Тести
І так, почнемо з найпростішого — часу затраченого на запуск. І тут одразу помічаємо дивні речі — OpenJ9, розробники якого обіцяли на 42% швидший за інші JVM старт, в реальності запускається в кілька разів довше. Заради справедливості хочу підмітити, що в графіку вказаний середній показник з 3 ітерацій бенчмарку, і найкращий результат OpenJ9 показав на третій ітерації, запустившись за 289 мілісекунд, що все ще надто багато.
Я довго намагався зрозуміти природу цього явища, і єдина ідея щодо можливої причини такої затримки — особливість мого бенчмарку, через яку час запуску рахується не після виклику main-функції, а в конструкторі об’єкта тесту «Startup», який в свою чергу викликається в статичному конструкторі main-класу. Можливо, OpenJ9 містить оптимізації, які впливають на чергу ініціалізації класів, але це лише теорія.
Серед інших JVM кращі результати показали OpenJDK та її модифікації.
По результатам тесту на використання ОЗП, помічаємо що всі дистрибуції HotSpot JVM впорались майже ідентично з рівнем споживання оперативної пам’яти приблизно 2МБ на старті і 20МБ при завршенні бенчмарку. OpenJ9 знов неприємно дивує, споживаючи аж 65МБ одразу після запуску JVM.
Далі проаналізуємо оверхед JIT компіляції. Фактично це різниця між часом, витраченим на перший та повторний запуск одного нескладного метода. Як бачимо, HotSpot витрачає на компіляцію метода в середньму від 2 до 4 мілісекунд. OpenJ9 демонструє трохи більші показники, але теж в рамках допустимого.
Тут можемо побачити результати заміру витрати часу на виконання доволі складного метода з великим циклом і математичними операціями. Цифри по осі X означають номер ітерації виклику метода в рамках однієї ітерації бенчмарку. OpenJ9 демонструє набагато меншу швидкість виконання, ніж JVM на базі HotSpot. Також на графіку можна побачити результат роботи оптимізацій JIT-компілятора: перший виклик метода займає найбільшу кількість часу, а з кожним наступним викликом час виконання зменшується.
Якщо відкинути результати OpenJ9 та подивитись на продуктивність інших JVM ближче, можемо побачити приблизно однакову картину.
Час відгуку JNI на першій ітерації у половини з протестованих JVM значно більший ніж у іншої. Цей показник може бути критичним наприклад при розробці ігор з використанням LWJGL, або просто програм, які в значній мірі полягаються на нативні бібліотеки.
Якщо відкинути час відгуку на першій ітерації, бачимо приблизно однакові результати для всіх JVM.
При вимірюванні часу, затраченого на виклик метода через рефлексію, несподівано бачимо відсутність значної різниці між першою та наступними ітераціями в OpenJ9.
Але варто лише відкинути результати першої ітерації, і ми бачимо, що інші реалізації JDK мають в цілому кращу продуктивність при роботі з рефлексією.
І останній на сьогодні тест — побайтове копіювання заповненого випадковими даними масиву байт розміром в 5 мегабайт з однієї змінної в іншу. Результат ви бачите самі.
Резюмуючи
Насправді виділити явного переможця в цих тестах складно. Проте за допомогою них можна побачити сильні та слабі сторони кожної JVM. В будь-якому випадку треба розуміти, що жодні синтетичні тести не можуть показати реальну картину продуктивності роботи JVM з саме вашим кодом та на вашому проєкті.
Для тих, хто бажає подивитись на точні цифри, надаю повні результати бенчмаркінга для кожної з JVM:
5 коментарів
Додати коментар Підписатись на коментаріВідписатись від коментарів