Розкриваємо чорний ящик: JVM зсередини



Осінь – чудовий час для зустрічі зі старими друзями, поїздок на конференції, прогулянок парками. Багато хто вже повернулися з відпусток з новими враженнями, ідеями, готові ділитися ними, спілкуватися з оточуючими. Наше сьогоднішнє інтерв'ю не про подорож, хоча, безсумнівно, занурення у світ Java теж можна назвати таким. Розмова піде про JVM. Наш співрозмовник – Charles Nutter з Red Hat.

Отже, запасаємося кави і починаємо.

— Наша тема сьогодні – це JVM і її «темний» вміст. Charles, добрий день! Скажіть, коли для вас JVM перестала бути загадкою?

– Добрий.

Так, відчуття роботи з чорним ящиком, існує у більшості користувачів віртуальної машини Java, з якими я знайомий.

Думаю, що процес вивчення у мене почався, коли був випущений OpenJDK з відкритим вихідним кодом. Приблизно в цей час я став розбиратися, як працює JVM. На той момент за спиною було вже десять років стажу розробника. Інтерес полягав у тому, щоб зрозуміти, що насправді відбувається «за лаштунками», в ключових місцях JVM. Не скажу, що на той момент я копирсався саме в нутрощах віртуальної машини Java.

Все змінилося під час роботи над JRuby, реалізацією Ruby, працюючої на JVM.

Для того щоб зробити мову корисним і потужним, ми стали пильно вивчати JVM, ті найпотаємніші місця віртуальної машини. Розуміння роботи JVM потрібно для опрацювання алгоритмів оптимізації.

Спільно з інженерами, що працюють над JVM, ми розробляли функції, наприклад, такі як invokedynamic, які допомагають функціональним мовам, в нашому випадку, JRuby.

Таким чином після десяти років роботи над JRuby, я отримав знання і досвід того, як працює JVM, і зробив кілька з цих темних плям трохи менше темними.

— Що ви думаєте про застарілою, але вперто засіла в голові людей ідеї, що Java – це повільно? Наскільки начинка відповідає можливостей апаратних засобів на сьогоднішній день?

– Правда полягає в тому, що це питання порушувалося часто і нами як учасниками проекту JRuby. Люди, які не знайомі з Java або з JVM, почули про ідею реалізації Ruby на ній: Ruby – мова, яка не вважається швидким, на Java, яка, на жаль, має некоректну, застарілу репутацію у вигляді повільності. В такому виконанні мова не мав сенсу для багатьох людей.

Нам довелося вирішувати це питання. Правда полягає в тому, що Java була повільною п'ятнадцять років тому. Величезна робота над JIT-компіляторами і збирачем сміття тривала і триває по сей день, кожен день. Залишилося багато людей, які були в індустрії і пам'ятають «недобрі часи» повільної Java. Через це міф так довго не зникає.

В наші дні Java дуже потужна, але швидкість і багато чудових можливостей залежать від JIT-компіляторів і збирача сміття, що часто веде до втрат при запуску.

Однак і сьогодні Java є, що покращувати, оптимізувати, наприклад – повинно бути знижений час кривий прогріву для отримання максимальної, пікової продуктивності. На щастя, над цими речами триває копітка робота.

— Ви згодні з такою заявою: одна з причин в тому, що багато розробники приділяють мало часу вивченню внутрішньої будови і роботи JVM, що програми чудово виконуються в різних середовищах і їх не потрібно переписувати і оптимізувати під кожну платформу?

– Великий плюс JVM полягає в тому, що, одержуючи у своє розпорядження так званий чорний ящик, в більшості випадків розробнику не потрібно заглядати під кришку, щоб зрозуміти, як влаштована JVM, як вона працює. Однак, як і в будь-яких операційних системах, мовами програмування, бібліотеках, фреймворках, які ви використовуєте, знання про те, як вони працюють, роблять вас краще, досвідченішими.

В моєму випадку ми були змушені зрозуміти, чому JVM не завжди така швидка, якою ми хочемо її бачити. Потрібно було розбиратися, які дії потрібно виконати, щоб навчити Ruby «бігти» стрімко.

Настала необхідність заглянути всередину JVM і зрозуміти, як вона працює, від і до.
Багато розробники ніколи не добираються до цієї точки дослідження. Ви знаєте, як працює збирач сміття, JIT-компілятори, іноді цього достатньо. Це нормально, коли ви не знаєте, що відбувається всередині, коли ви розробляєте програми. Але зустрічаються випадки, коли вам може знадобитися максимальна продуктивність або інші критичні речі для великого бізнесу, для деяких веб-сайтів, в цей самий момент вам будуть потрібні деталі, які ви отримаєте тільки під час «занурення».

— А може бути, це правильно, що розробники не заглядають в налаштування JVM, поки не побачать проблему? Це час можна з користю витратити для написання нових програм, не так?

– Так, я згоден, у цьому якраз і полягає реальна сила віртуальної машини Java. І це було однією з головних причин, чому Java так швидко розвивалася останні двадцять років. Люди можуть швидко розробляти програми, дивно швидко.

Очевидно, що я ніколи не рекомендував би кожному копатися в роботі JIT-компілятора або читати код збирача сміття. Існує багато особливостей, про які необхідно знати та розуміти їх, але це не завжди може придатися для щоденної розробки.

Я планую на Joker 2016 розповісти багато цікавого, наприклад, як можна зазирнути за лаштунки JVM… як можна включити JVM JIT-логування і подивитися, як код компілюється, побачити, які рішення приймає машина під час оптимізації. Можна піти ще далі і почати дивитися код на асемблері, якщо у вас є алгоритм або програма, яку ви хочете оптимізувати. Вам не потрібно буде дуже глибоко занурюватися в пучину JVM, щоб прийти до кращого розуміння того, як вона працює і як змусити працювати JVM для вашого додатки на всі сто відсотків.

— Під час нашого діалогу у мене з'явився ще одне питання, на перший погляд, не стосується JVM. Як ви думаєте, модулі і модулярная система, що плануються до виходу в Java 9, допоможуть в питаннях оптимізації?

– Я стежив за процесом модуляризації JVM. Про поділ на дрібні частини для легкого розподілу йшли розмови весь час, поки я працював у Sun Microsystem. Я думаю, що це дивовижна і одночасно складна робота, яка відбувається зараз, з урахуванням того величезного обсягу коду і в тому числі у внутрішній структурі JVM. Вбудувати весь runtime в цілу платформу на JVM – це величезна складність.

Існує велика кількість залежностей в рамках основних класів JDK з класами, яких ми не бачимо зі «сцени». Чим я дійсно захоплююся у модулярности – так це тим, що у нас буде точний шлях до обмеження певних блоків у додатку і всіх його залежностей. Як в Maven під час складання в даний час, тепер можна буде переносити програми з усіма іншими зручними інструментами, які скоро вийдуть в JDK 9.

Інша цікава особливість в JDK 9 – це оптимізація окремих елементів, можливість аналізу окремих частин коду і виконання предоптимизации. Це допоможе при завантаженні, збільшить інтенсивність прогрівання, можливо, виконання дострокової компіляції.

Більшість з цих речей було б складно реалізувати без модулярности, ми отримаємо набагато більше гнучкості після її впровадження.

— Як ми знаємо, існують статичні і динамічні компілятори. Чому з Just-In-Time(JIT) швидше? Розкажіть, будь ласка, як механізми JIT допомагають створювати більш швидкі послідовності інструкцій і робити заміну інструкцій на більш ефективні набори?

– Статичні компілятори завжди повинні йти на вимушений компроміс при прийнятті рішення про оптимізацію коду, так як їм важче зрозуміти, розібратися, яким чином програма буде вести себе під час виконання. В цьому і перевага JIT-компіляторів: вони збирають інформацію про використовуваних об'єктах, гілках і викликаються методи, де виконується найбільше коду. JIT-компілятори можуть використовувати трюки, такі як вбудовування для об'єднання методів і деоптимизация, які дозволяють провести агресивну оптимізацію коду з безпечним відкатом (для прикладу, на інтерпретатор або менш оптимізовану версію коду) у разі, якщо ці оптимізації необхідно змінити.

— Ще одна важлива частина в роботі JVM – це збирач сміття. Кілька місяців тому я читав замітку про «Shenandoah garbage collection technology». «Shenandoah is a parallel and concurrent compacting garbage collector. Parallel meaning we use multiple threads to get the GC work done faster, and concurrent meaning we do work while the Java threads are running,» said Kennke, who is working on Shenandoah with Red Hat engineer Christine Flood.

Ви можете розповісти нам про роботу в цьому напрямку?


– Я володію інформацією про проект Shenandoah тільки в рамках того, що прочитав сам, але я вітаю моїх друзів в Red Hat в ідеї вийти за обмеження OpenJDK.
Вибір збирача сміття є однією з найбільш складних проблем користувачів JVM. Shenandoah потрапляє в групу збирачів сміття, орієнтованих на короткі паузи для великих куп (heap), це особливо актуально зараз, в епоху великих даних. Він намагається поліпшити аспекти збирачів сміття CMS і G1, забезпечуючи шляхом одночасного ущільнення купи (затикаючи дірки відразу після складання об'єктів) і використання альтернативних стратегій для виправлення об'єктів, в той час як додаток продовжує працювати. Безсумнівно, варто вивчити Shenandoah, якщо у вас великий heap і необхідно звести паузи до мінімуму.

— Існує можливість «тонкої» настройки збирача сміття? Наскільки виправдане використання різних збирачів сміття (GC) і в яких випадках цю можливість необхідно використовувати? Що ви можете сказати про CMS GC і G1 GC? Який «тюнінг» можна використовувати для налаштування?

Було цікаво спостерігати, як збирач сміття Concurrent Mark-Sweep почав повільно поступатися G1. Перший був робочою конячкою для багатьох великих JVM проектів, незважаючи на необхідність налаштування пачки неочевидних прапорів або прийняття більш частих подій «concurrent failure mode», що призводять до пауз в роботі системи. G1 впевнено зростає протягом останніх кількох років, і тепер, видається більш популярним варіантом для великих heap'ів і низьких пауз. Ось і невелика рекомендація, як я розумію, G1 є більш терпимим до установок за замовчуванням. Налаштування збирача сміття навряд чи коли-небудь піде, але мені здається, що тренд полягає у виконанні специфічних завдань складальником сміття без надмірного втручання користувачів.

— Ми приділили увагу таким центральним темами робота з пам'яттю, компиляторам і збирачі сміття. Може, ми щось упустили, і Java не стала для нас зрозуміліше? Про що ще варто обов'язково розповісти, показуючи Java зсередини?

Цікаво знати, як сама JVM працює, з його кодом, JIT-компіляторами, моделлю пам'яті і збирачами сміття, але багато з найцікавіших частин Java живуть в середніх шарах. Кожен розробник Java повинен мати хороше знання JVM байт-коду, від його початкової структури до моменту виконання віртуальною машиною.

Я думаю, що більшість розробників Java захочуть дізнатися, як invokedynamic (доданий в Java 7) збільшує можливості нових мов на JVM і новим фішках для Java. Важливо мати загальне розуміння платформи, навіть якщо ви ніколи не будете занурюватися глибоко в який-небудь шар.

— Наостанок хотілося б дізнатися трохи про нововведення, які чекають нас в 9 версії, таких як JVMCI and graal.

OpenJDK 9 принесе з собою новий API під назвою JVMCI. За допомогою цього API JIT-компілятор, що використовується JVM для оптимізації коду, може бути змінений за допомогою командного рядка. Цей варіант буде знаком для людей, які коли-небудь переставляли на інший GC, для тих з нас, хто пам'ятає боротьбу з «server» і «client» прапорами кілька років тому. Це дозволить дослідити JIT-компілятори, такі як новий Graal (написаний на Java JIT компілятор, готовий конкурувати з власним HotSpot JIT), без перенастроювання JVM. Graal, в свою чергу, використовується для пошуку нових шляхів реалізації високопродуктивних мов на JVM, включаючи нову реалізацію Ruby, розроблену пліч-о-пліч з проектом JRuby. Зараз дуже захоплююче час для того, щоб бути на платформі Java!

— Величезне спасибі за бесіду.




14 і 15 жовтня (Joker 2016 вже через тиждень!) Чарльз виступить з двома хардкорными доповідями: кейноутом From Java to Assembly: Down the Rabbit Hole доповіддю let's Talk About Invokedynamic.

Крім того, якщо ви любите «кішочкі» JVM так само, як ми, то крім доповідей Чарльза Наттера рекомендуємо вам переглянути наступні доповіді Joker 2016:

Джерело: Хабрахабр

0 коментарів

Тільки зареєстровані та авторизовані користувачі можуть залишати коментарі.