Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

AOT-компиляция Java

321 views

Published on

http://techtalks.nsu.ru
Видеозапись: http://www.youtube.com/watch?v=blXQTBiYbzs"
10 декабря 2014. Никита Липский (Excelsior) рассказывает про AOT-компиляцию

Ahead-of-time (AOT) компиляция, или статическая компиляция, не так давно объявлена компанией Oracle как одно из нововведений Java 9 — следующего мажорного релиза Java. Это объявление вызвало разнообразную реакцию в сообществе Java-программистов: некоторые удивляются почему только сейчас, кто-то в недоумении, потому что всегда считал, что AOT-компилятор для Java не возможен теоретически из-за богатых динамических возможностей Java, многие убеждены, что AOT не нужен для Java, потому что он не может конкурировать по производительности с JIT, который использует динамический профиль исполнения для оптимизации программ на лету.

В этом докладе я попробую развеять распространенные мифы, которые сложились вокруг AOT-компиляции Java, расскажу почему AOT-компиляция возможна с сохранением всех динамических особенностей Java, покажу где этот подход имеет преимущества в производительности перед динамической компиляцией (JIT) с технической точки зрения, а также обрисую для чего вообще может быть полезна AOT-компиляция для Java.

Лекция прочитана в рамках проекта Tech Talks @NSU – серии открытых лекций о разработке ПО и карьере в IT, проводимых в Новосибирском государственном университете.

Подробности: http://techtalks.nsu.ru

Published in: Technology
  • Be the first to comment

  • Be the first to like this

AOT-компиляция Java

  1. 1. AOT  компиляция  Java     Никита Липский Excelsior 1
  2. 2. ÄДàаâвíнûыìм äдàаâвíнîо   2
  3. 3. ÄДàаâвíнûыìм äдàаâвíнîо, ÂВîо âвðрåеìмåеíнàа ÑС+++ ++++++   3
  4. 4. ÄДàаâвíнûыìм äдàаâвíнîо, ÂВîо âвðрåеìмåеíнàа ÑС+++, ÂВñсåе êкîоìмïпèиëлÿяòтîоðрûы áбûыëлèи ñсòтàаòтèи÷чåеñсêкèиåе ++++++   4
  5. 5. ÏПîоêкàа íнåе ïпîоÿяâвèиëлàаñсüь..   5
  6. 6. ÏПîоêкàа íнåе ïпîоÿяâвèиëлàаñсüь Java   6
  7. 7. •  Интерпретация   •  Компиляция  в  машинный  код  и  исполнение   на  “железе”   Исполнение     Java  байткода  JVM   7
  8. 8. Трансляция  Java  to  Na@ve   •  Динамическая  (Just-­‐In-­‐Time  –  JIT).     – Трансляция  происходит  во  время  исполнения   программы   •  Статическая  (Ahead-­‐Of-­‐Time  –  AOT)   – Трансляция  происходит  до  исполнения   программы   8
  9. 9. 9
  10. 10. Статическая  компиляция  Java   •  Это  вообще  возможно?   –  Если  да,  то  при  каких  условиях  и  будет  ли  это  все  еще   называться  Java?   •  Зачем  это  нужно?   –  Обфускация  vs.  статическая  компиляция   –  Старт  приложения   –  Уменьшение  размера  дистрибутива  Java  приложения   без  зависимостей  от  Java   –  Производительность:  какие  преимущества  перед  JIT   компиляцией   –  Почему  AOT  лучше  для  Desktop,  Embedded,  Mobile   –  Есть  ли  выгода  от  применения  AOT  на  server  side   10
  11. 11. 11
  12. 12. Кому  нужен  AOT  для  Java?     Кто знает про Excelsior JET?Кто знает про Excelsior JET? 12
  13. 13.   Мифы  вокруг  статической   компиляции  Java   13
  14. 14. •  Reflecron   •  Динамическая  загрузка     Статическая  компиляция  невозможна?   Миф  1.     Java  -­‐    «слишком»  динамическая     14
  15. 15.   WORA:  Write  Once  Run  Anywhere   (пиши  раз,  исполняй  везде)   !=   BORA:  Build  Once?   (собирай  раз???  …)   Миф  2.  AOT  компиляция  –     убийца  WORA   15
  16. 16. ”Я  получу  (маленький)  исполняемый  файл,   который  будет  работать  без  JVM  (как  в   С)”     Но:   – Стандартные  классы?   –   GC,  reflecron?   Миф  3.  AOT  =  маленький  Exe   16
  17. 17.   Тем  не  менее,  используя  AOT,  можно   получить    дистрибутив  Java  приложения   без  зависимостей  от  Java  значительно   меньший,  чем  размер  JRE:     “Javа  худеет”:     h•ps://www.youtube.com/results? search_query=javaday+худеет     Миф  3.  AOT  =  маленький  Exe   17
  18. 18. Java  «слишком»  динамическая   18
  19. 19. •  Переопределяют  умолчательную  логику   разрешений  ссылок  между  классами   •  Уникальное  пространство  имен   •  Позволяют  управлять  зависимостями,  решая   проблемы  JAR  hell  (OSGi,  Java  Module  System)   •  Java  EE  сервера,  Eclipse  RCP,  плагины   Нестандартные  загрузчики  классов   19
  20. 20. Как  компилировать  статически?   •  Компилировать  каждый  класс  изолировано   от  других   – Плохо  для  производительности   •  Изучить  логику  разрешения  ссылок  для   популярных  загрузчиков   – Не  работает  для  произвольных  загрузчиков   Нестандартные  загрузчики  классов   20
  21. 21. Нестандартные  загрузчики  классов   Classes   21
  22. 22. Classes   CL1   CL2   CL3   CL4   Нестандартные  загрузчики  классов   CLi: classloader (загрузчик классов) 22
  23. 23. •  CL4  •  CL3   •  CL2  •  CL1   classes   classes   classes  classes   Нестандартные  загрузчики  классов   23
  24. 24. •  CL4  •  CL3   •  CL2  •  CL1   classes   classes   classes  classes   Нестандартные  загрузчики  классов   24
  25. 25. •  CL4  •  CL3   •  CL2  •  CL1   classes   classes   classes  classes   Нестандартные  загрузчики  классов   25
  26. 26. –  Картинка   •  CL4  •  CL3   •  CL2  •  CL1   classes   classes   classes   Нестандартные  загрузчики  классов   26
  27. 27. •  CL4  •  CL3   •  CL2  •  CL1   classes   classes   Нестандартные  загрузчики  классов   27
  28. 28. Схема  поддержки  загрузчиков  в  AOT:   •  Компонента  разрешения  ссылок  в  AOT     компиляторе:   –  Определяет,  какие  загрузчики  будут  созданы   во  время  исполнения  и  назначает  каждому   статический  ID   –  Разбивает  классы  приложения  по  загрузчикам     –  Разрешает  ссылки  между  классами     Нестандартные  загрузчики  классов   28
  29. 29. Схема  поддержки  загрузчиков  в  AOT:   •  Во  время  исполнения:   –  По  экземпляру  загрузчика  вычисляется  ID   –  Имея  статический  ID,  мы  можем  грузить   статически  скомпилированные  классы:   •  создание  экземпляра  класса  java.lang.Class   •  наполнение  его  рефлективной  информацией   •  загрузка  кода  осуществляется  OS   Нестандартные  загрузчики  классов   29
  30. 30. Зачем  AOT  для  Java?   30
  31. 31. Защита  кода  от  декомпиляции   31
  32. 32. •  Java  bytecode  легко  превращается  в   исходный  код   •  Процесс  обфускации  при  активном   использовании  reflecron  трудоемок  и   трудно  поддерживаем   •  Даже  по  обфусцированному  коду  часто   можно  понять,  что  код  делает  (ссылки  на   JDK  остаются  в  неизменном  виде)   Защита  кода  приложения   32
  33. 33. •  Машинный  код  можно  только  эффективно   дизассемблировать   •  По  дизассемблированному  коду  не  понять   структуру  приложения  (нет  имен  классов,   методов)   •  После  агрессивной  оптимизации   машинный  код  далек  от  оригинального   кода   Защита  кода  приложения   33
  34. 34. Время  старта  приложения   34
  35. 35. Во  второй  раз  приложение  стартует   значительно  быстрее,  чем  в  первый   – Загрузка  кода  и  данных  приложения  с  диска   – Загрузка  системных  и  сторонних  динамических   библиотек  (dll,  so)   Холодный  старт  vs  теплый   35
  36. 36.   Java  Quick  Start     •  Java  Quick  Start   – Предзагружает  rt.jar,  динамические   библиотеки   36
  37. 37. AOT  быстрее?   •  Машинный  код  “толще”  Java  bytecode   •  Загрузка  кода  с  диска  занимает  больше   времени,  чем  его  начальное  исполнение   37
  38. 38. AOT  быстрее!   •  Код  исполняемый  на  старте  –  в  начало   исполняемого  файла     •  Можно  предзагружать  стартовый  сегмент   последовательным  чтением   38
  39. 39. 39
  40. 40. Производительность   40
  41. 41.        “Скомпилировав  Java  статически,  мы   получим  скорость  приложения  как  в  C,  C     быстрее  Java,    следовательно  AOT  быстрее”       Миф  4.  AOT  быстрее   41
  42. 42.     “Эффективно  оптимизировать  Java   приложения  можно  только  на  основе   динамического  профиля  исполнения”       Миф  5.  JIT  быстрее   42
  43. 43. –  Протяжка  констант   –  Удаление  избыточного  кода   –  Удаление  общих   подвыражений   –  Открытая  подстановка   –  Специализация  методов   –  Развертывание  циклов   –  Версионирование  циклов   –  Вынос  инвариантов   –  Удаление  хвостовой   рекурсии   –  Девиртуализация  вызовов   –  Аллокация  объектов  на   стэке  и  их  взрыв   –  Удаление  проверок   времени  исполнения   –  Удаление  избыточной   синхронизации   –  Оптимальная  выборка   кода  и  свертка   шаблонов   –  Планировка   инструкций   –  Оптимальное   распределение   регистров   Виды  оптимизаций   43
  44. 44. Java  –  ООП   • Много  методов   • Методы  маленькие  (get/set)   • Методы  по  умолчанию  ВИРТУАЛЬНЫЕ   44
  45. 45. •  Предусловие  дальнейшей  открытой  подстановки   (inline)   •  Анализ  иерархии  классов     – метод  не  перегружается  –  невиртуальный   •  Типовый  анализ   – new T().foo(); //вызов foo() невиртуальный •  Inline  caches   Девиртуализация  вызовов   45
  46. 46. A a; …                                                  è     a.foo();   if (RT_Type(a) in CHA) { inlined body of foo() } else { a.foo(); } Идея: метод не перегружается – невиртуальный Анализ  иерархии  классов  (CHA)   46
  47. 47. A a; //A – формальный тип Если  A –  формальный  тип  переменой  a,     то  во  время  исполнения  в  a  могут  находится  значения  типа   наследника  A.      Такие  типы  называются  фактическими.   A a = new B(); //B – фактический тип   Источником  фактических  типов  для  статического  анализа   являются  операторы  new.     Формальный  vs  фактический  тип     47
  48. 48. Идея:     new A().foo();  //невиртуальный  вызов       Типовый  анализ   48
  49. 49. A a = b? new B() : new C(); a.foo();   Если  foo()  в  B  и  С один  и  тоже,  то     a.foo() невиртуальный  вызов                                        (можно  инлайнить)   Типовый  анализ   49
  50. 50. A a = b? bar() : baz(); … a.foo();   Если  bar() возвращает  только  new B,                  а  baz()                                экземпляры  new С,  то     a.foo() - опять  невиртуальный  вызов                                                        (можно  инлайнить)   Типовый  анализ   50
  51. 51.     Откуда  мы  знаем,  что  возвращает  bar() и   baz()?   Типовый  анализ   51
  52. 52. •  Глобальный  анализ  –  анализирует  все   методы  программы,  вычисляя  про  каждый   метод  полезную  информацию     •  Результаты  глобального  анализа   используются  для  оптимизации   конкретного  метода       Глобальный  анализ   52
  53. 53. •  Все  Java  объекты  создаются  в  динамической   памяти  –  Java  heap  (куча)   •  Большинство  объектов  временные   •  Хочется  их  размещать  на  стэке  метода   •  Escape  анализ  (анализ  утечек)  –  определяет   утекает  ли  объект  в  разделяемую  память.   Аллокация  объектов     на  стэке   53
  54. 54. void foo() { for (Object o: getCollection()) { doSomething(o); } } Пример     54
  55. 55. void foo() { Iterator iter = getCollection().iterator(); while (iter.hasNext()) { Object o = iter.next(); doSomething(o); } } Пример     55
  56. 56. void foo() { ArrayList list = getCollection(); Iterator iter = list.iterator(); while (iter.hasNext()) { Object o = iter.next(); doSomething(o); } } Пример     56
  57. 57. void foo() { ArrayList list = getCollection(); ArrayList.ListItr iter = new ListItr(list); while (iter.hasNext()) { Object o = iter.next(); doSomething(o); } } Пример     57
  58. 58. void foo() { ArrayList list = getCollection(); ArrayList.ListItr iter = onStack ListItr(); iter.this$0 = list; iter.cursor = 0; iter.size = list.elemData.length; while (iter.hasNext()) { Object o = iter.next(); doSomething(o); } } Пример     58
  59. 59. void foo() { ArrayList list = getCollection(); ArrayList.ListItr iter = onStack ListItr(list); iter.this$0 = list; iter.cursor = 0; iter.size = list.elemData.length; while (iter.cursor < iter.size) { int index = iter.cursor++; Object o = iter.this$0.elemData[index]; doSomething(o); } } Пример     59
  60. 60. void foo() { ArrayList list = getCollection(); int cursor = 0; int size = list.elemData.length; while (cursor < size) { Object o = list.elemData[cursor++]; doSomething(o); } } Пример     60
  61. 61. void foo() { ArrayList list = getCollection(); int size = list.elemData.length; for (int i = 0; i < size; i++) { doSomething(list.elemData[i]); } } Пример     61
  62. 62. •  Часто  бывают  довольно  сложными     •  Требуют  итеративного  пересчета   •  Глобальный  анализ  зависит  от  ВСЕЙ  программы.   Анализ  и  оптимизации   62
  63. 63. •  Часто  бывают  довольно  сложными     •  Требуют  итеративного  пересчета   •  Глобальный  анализ  зависит  от  ВСЕЙ  программы.   Все  ли  это  может   себе  позволить  JIT?   Анализ  и  оптимизации   63
  64. 64. •  Часто  бывают  довольно  сложными     •  Требуют  итеративного  пересчета   •  Глобальный  анализ  зависит  от  ВСЕЙ  программы.   Все  ли  это  может   себе  позволить  JIT?   Анализ  и  оптимизации   64
  65. 65. •  Часто  бывают  довольно  сложными     •  Требуют  итеративного  пересчета   •  Глобальный  анализ  зависит  от  ВСЕЙ  программы.   Все  ли  это  может   себе  позволить  JIT?   Анализ  и  оптимизации   65
  66. 66. •  Профилировка  и    селективная  компиляция   •  Открытая  подстановка  на  основе  профиля   исполнения     •  Оптимизация  трасс  исполнения   •  Выбор  оптимальных  инструкций   Динамические  оптимизации   66
  67. 67. •  А  что  будет,  если  у  приложения  нет  ярко   выраженного  горячего  кода?   •  Долгий  прогрев,  результаты  прогрева  не   используются  при  дальнейших  стартах   приложения   Горячий  код  vs  теплый   67
  68. 68. JFCMark  (Short  Run)   0%   50%   100%   150%   200%   250%   2  core  Celeron,  2.60Ghz   4  core  i5,  3.8GZ   Excelsior  JET   HotSpot  client   HotSpot  server   68
  69. 69. JFCMark  (Long  Run)   0%   20%   40%   60%   80%   100%   120%   140%   160%   2  core  Celeron,  2.60Ghz   4  core  i5,  3.8GZ   Excelsior  JET   HotSpot  client   HotSpot  server   69
  70. 70.   Может  ли  статический  компилятор   использовать  динамический  профиль   исполнения?   Динамические  оптимизации   70
  71. 71. Server  side   •  Процессорное  время  в    облаках  –  дорого     •  Через  некоторое  время  работы  сервера   профиль  исполнения  стабилизируется   •  Почему  этот  профиль  не  передать   статическому  компилятору?   71
  72. 72. •  Кроме  кода  приложения,  есть  еще  код  JVM   –  Управление  памятью   –  Сборка  мусора   –  Потоки  и  синхронизация   –  Обработка  исключительных  ситуаций   –  …   •  Кроме  Java  кода,  есть  сторонний  код     –  Narve  методы  +  нативные  библиотеки  (в  т.ч.  ОС)   Не  кодом  единым  …   72
  73. 73. Embedded   •  Чем  слабее  железо,  тем  дороже   динамическая  компиляция   •  Встроенные  системы  часто  не  обладают   теми  же  вычислительными  мощностями,   что  и  настольные  компьютеры/сервера     73
  74. 74. Mobile   •  JVM  on  Mobile:   74
  75. 75. Mobile   •  JVM  on  Mobile:   – Платформенные  классы   75
  76. 76. Mobile   •  JVM  on  Mobile:   – Платформенные  классы   – GC  и    Memory  Manager   76
  77. 77. Mobile   •  JVM  on  Mobile:   – Платформенные  классы   – GC  и    Memory  Manager   – Reflecron   77
  78. 78. Mobile   •  JVM  on  Mobile:   – Платформенные  классы   – GC  и    Memory  Manager   – Reflecron   – JIT   78
  79. 79. Mobile   •  JVM  on  Mobile:   – Платформенные  классы   – GC  и    Memory  Manager   – Reflecron   – JIT   Чего  не  хватает?   79
  80. 80. Mobile   •  JVM  on  Mobile:   – Платформенные  классы   – GC  и    Memory  Manager   – Reflecron   – JIT   Зарядки!     80
  81. 81. Mobile   •  У  беспроводных  устройств  есть  БАТАРЕЙКА     •  Стоит  ли  ее  тратить  на  динамическую   компиляцию?   81
  82. 82. iOS   •  Политика  распространения  приложений  на   iOS  запрещает  любую  динамическую   загрузку  кода   •  Для  Java  возможен  либо  интерпретатор,   либо  AOT       82
  83. 83. AOT  компиляторы  для  Java   GCJ Excelsior JET Android ART RoboVM Avian CodeNameOne IBM J9 Java ME 83
  84. 84. 84
  85. 85. Статическая  компиляция  Java     •  возможна   –  с  сохранением  всех  возможностей  Java   –   даже  в  присутствии  нестандартных  загрузчиков  классов     •  полезна     –  для  защиты  кода   –  быстрого  старта   –  лучшего  UX   –  улучшения  производительности   –  экономии  батарейки,  памяти,  диска   Итоги   85
  86. 86. Вопросы и ответы Никита Липский, Excelsior nlipsky@excelsior-usa.com twitter: @pjBooms 86
  87. 87. Ускорение  приложений   87

×