Бөлісу құралы:


Причины перехода на Java 11 и выше

Вопрос заключается не в том, следует ли перейти на Java 11 или более позднюю версию, а когда. В течение следующих нескольких лет Java 8 больше не будет поддерживаться, и пользователям придется перейти на Java 11 или более поздней версии. Мы утверждают, что есть преимущества для перехода на Java 11 и поощрять команды сделать это как можно скорее.

С момента java 8 добавлены новые возможности и усовершенствования. Существуют заметные дополнения и изменения в API, а также улучшения, которые улучшают использование запуска, производительности и памяти.

Переход на Java 11

Переход на Java 11 можно сделать поэтапно. Коду не требуется использовать модули Java для запуска на Java 11. Java 11 можно использовать для запуска кода, разработанного и созданного с помощью JDK 8. Но существуют некоторые потенциальные проблемы, в первую очередь касающиеся устаревших API, загрузчиков классов и отражения.

Группа инженеров Microsoft Java содержит руководство по переходу с Java 8 на Java 11. Руководство по миграции Java Platform, Standard Edition Oracle JDK 9 и состояние системы модулей: совместимость и миграция являются другими полезными руководствами.

Высокоуровневые изменения между Java 8 и 11

Этот раздел не перечисляет все изменения, внесенные в Java версии 9 [1], 10 [2], и 11 [3]. Выделены изменения, влияющие на производительность, диагностику и продуктивность.

Модули [4]

Модули устраняют проблемы конфигурации и инкапсуляции, которыми трудно управлять в крупномасштабных приложениях, работающих на classpath. Модуль — это самоописывающая коллекция классов и интерфейсов Java и связанных ресурсов.

Модули позволяют настраивать конфигурации среды выполнения, содержащие только компоненты, необходимые приложению. Эта настройка создает меньший объем и позволяет статически связать приложение с помощью jlink в специальную среду выполнения для развертывания. Это меньшее пространство может быть особенно полезным в архитектуре микрослужб.

Внутри системы JVM может воспользоваться преимуществами модулей таким образом, чтобы повысить эффективность загрузки класса. Результатом является среда выполнения, которая меньше, легче и быстрее запускается. Методы оптимизации, используемые JVM для повышения производительности приложения, могут быть более эффективными, так как модули кодируют необходимые компоненты класса.

Для программистов модули помогают обеспечивать строгую инкапсуляцию, требуя явного объявления, какие пакеты экспортируются модулем и какие компоненты ему необходимы, и путем ограничения доступности через отражение. Этот уровень инкапсуляции делает приложение более безопасным и удобным для обслуживания.

Приложение может продолжать использовать classpath и ему не нужно переходить на модули для работы на Java 11.

Профилирование и диагностика

Записыватель полетов Java [5]

Java Flight Recorder (JFR) собирает диагностические данные и данные профилирования из работающего приложения Java. JFR мало влияет на работающее приложение Java. Собранные данные затем можно проанализировать с помощью Java Mission Control (JMC) и других средств. В то время как JFR и JMC были коммерческими функциями в Java 8, оба являются открытым кодом в Java 11.

Управление миссиями Java [6]

Java Mission Control (JMC) предоставляет графическое отображение данных, собранных Java Flight Recorder (JFR) и является открытым исходным кодом в Java 11. Помимо общих сведений о работающем приложении JMC позволяет пользователю детализировать данные. JFR и JMC можно использовать для диагностики проблем со средой выполнения, таких как утечка памяти, затраты на сборку GC, горячие методы, узкие места потока и блокировка операций ввода-вывода.

Единое ведение журнала [7]

Java 11 имеет общую систему ведения журнала для всех компонентов JVM. Эта унифицированная система ведения журнала позволяет пользователю определить, какие компоненты следует регистрировать, а также на каком уровне. Это подробное ведение журнала полезно для выполнения анализа первопричин при сбоях JVM и диагностике проблем с производительностью в рабочей среде.

Профилирование кучи с низкой нагрузкой [8]

Новый API был добавлен в интерфейс инструментов виртуальной машины Java (JVMTI) для сбора выборочных данных о выделении кучи Java. Выборка имеет низкую нагрузку и может быть активирована на постоянной основе. Хотя выделение кучи можно отслеживать с помощью Java Flight Recorder (JFR), метод выборки в JFR работает только для выделений. Реализация JFR также может пропустить выделения ресурсов. В отличие от этого, выборка кучи в Java 11 может предоставлять сведения о живых и мертвых объектах.

Поставщики службы "Мониторинг производительности приложений" (APM) начинают использовать эту новую функцию, и группа инженеров Java изучает его потенциальное использование с инструментами мониторинга производительности Azure.

StackWalker [9]

При журналировании часто делают снимок стека текущего потока. Проблема заключается в том, какую часть трассировки стека записывать в журнал и стоит ли вообще регистрировать трассировку стека. Например, может потребоваться просмотреть трассировку стека только для определенного исключения из метода. Класс StackWalker (добавленный в Java 9) предоставляет моментальный снимок стека и предоставляет методы, которые дают программисту точный контроль над использованием трассировки стека.

Сборка мусора [10]

Следующие сборщики мусора доступны в Java 11: Serial, Parallel, Garbage-First и Epsilon. Сборщиком мусора по умолчанию в Java 11 является сборщик мусора G1 (Garbage First).

Три других коллекционера упоминаются здесь для полноты. Сборщик мусора Z (ZGC) — это одновременный сборщик с низкой задержкой, который стремится поддерживать время пауз менее 10 мс. ZGC доступен в качестве экспериментальной функции в Java 11. Сборщик Shenandoah — это сборщик с низкими паузами, который сокращает время пауз GC, выполняя больше сборки мусора одновременно с работой программы Java. Shenandoah является экспериментальной функцией в Java 12, но есть обратные порты к Java 11. Параллельный сборщик мусора Mark and Sweep (CMS) доступен, но устарел с версии Java 9.

JVM задает параметры GC по умолчанию для среднего варианта использования. Часто эти параметры по умолчанию и другие параметры GC необходимо настроить для оптимальной пропускной способности или задержки в соответствии с требованиями приложения. Для правильной настройки GC требуются глубокие знания о GC, опыт, который предоставляет группа инженеров Microsoft Java .

G1GC

Сборщик мусора по умолчанию в Java 11 — сборщик мусора G1 (G1GC). Целью G1GC является балансировка задержки и пропускной способности. Сборщик мусора G1 пытается достичь высокой пропускной способности, обеспечивая удовлетворение целевых значений пауз с высокой вероятностью. G1GC предназначен для предотвращения полных коллекций, но когда одновременные коллекции не могут быстро восстановить память достаточно быстро, резервная полная сборка будет происходить. Полный GC использует то же количество параллельных рабочих потоков, что и молодые и смешанные коллекции.

Параллельная GC

Параллельный сборщик является сборщиком по умолчанию в Java 8. Параллельный сборщик мусора — это сборщик с высокой пропускной способностью, использующий несколько потоков для ускорения процесса сборки мусора.

Epsilon [11]

Сборщик мусора Epsilon обрабатывает выделения, но не освобождает память. Когда куча исчерпана, JVM завершит работу. Epsilon полезен для краткосрочных сервисов и для приложений, которые считаются работоспособными без сбора мусора.

Улучшения контейнеров Docker [12]

До Java 10 ограничения памяти и ЦП, заданные в контейнере, не были распознаны JVM. Например, в Java 8 JVM по умолчанию максимальный размер кучи составляет 1/4 физической памяти базового узла. Начиная с Java 10, JVM использует ограничения, заданные группами управления контейнерами (cgroups), чтобы задать ограничения памяти и ЦП (см. примечание ниже). Например, максимальный размер кучи по умолчанию составляет 1/4 ограничения памяти контейнера (например, 500 МБ для -m2G).

Кроме того, были добавлены параметры JVM, чтобы предоставить пользователям контейнеров Docker точный контроль над объемом системной памяти, которая будет использоваться для кучи Java.

Эта поддержка включена по умолчанию и доступна только на платформах под управлением Linux.

Замечание

Большая часть работы по включению cgroup была портирована в Java 8 в версии jdk8u191. Дальнейшие улучшения могут не обязательно быть перенесены в версию 8.

Jar-файлы с несколькими выпусками [13]

В Java 11 можно создать JAR-файл, содержащий несколько версий файлов классов, относящихся к Java. Jar-файлы с несколькими выпусками позволяют разработчикам библиотек поддерживать несколько версий Java без отправки нескольких версий JAR-файлов. Для потребителей этих библиотек файлы JAR-файлов с несколькими выпусками решают проблему сопоставления определенных JAR-файлов с определенными целевыми объектами среды выполнения.

Другие улучшения производительности

Следующие изменения в JVM оказывают непосредственное влияние на производительность.

  • JEP 197: сегментованный кэш кода [14] — делит кэш кода на отдельные сегменты. Эта сегментация обеспечивает более эффективное управление объемом памяти JVM, сокращает время сканирования скомпилированных методов, значительно уменьшает фрагментацию кэша кода и повышает производительность.

  • JEP 254: компактные строки [15] — изменяет внутреннее представление строки из двух байтов на чар на один или два байта на чар, в зависимости от кодировки char. Поскольку большинство строк содержат символы ISO-8859-1/Latin-1, это изменение фактически сокращает объем пространства, необходимого для хранения строки.

  • JEP 310: Совместное использование Class-Data приложения [16] — Совместное использование Class-Data уменьшает время запуска, позволяя архивным классам размещаться в памяти во время выполнения. Расширение совместного использования данных классов приложений (Application Class-Data Sharing) увеличивает возможности класс-данных, позволяя классы приложений размещать в архиве CDS. Если несколько виртуальных машин JVM совместно используют один и тот же архивный файл, память сохраняется, а общее время отклика системы улучшается.

  • JEP 312: Thread-Local рукопожатия [17] — позволяет выполнять обратный вызов на потоках без выполнения глобальной безопасной точки, что помогает виртуальной машине снизить задержку, уменьшая частоту глобальных безопасных точек.

  • Отложенное выделение потоков компилятора [18] — в многоуровневом режиме компиляции виртуальная машина запускает большое количество потоков компилятора. Этот режим используется по умолчанию в системах с большим количеством ЦП. Эти потоки создаются независимо от доступной памяти или количества запросов компиляции. Потоки потребляют память, даже если они неактивны (это почти все время), что приводит к неэффективному использованию ресурсов. Чтобы устранить эту проблему, реализация была изменена, чтобы запустить только один поток компилятора каждого типа во время запуска. Запуск дополнительных потоков и завершение работы неиспользуемых потоков обрабатывается динамически.

Следующие изменения в основных библиотеках влияют на производительность нового или измененного кода.

  • JEP 193: обработчики переменных [19] — определяет стандартный способ вызова эквивалентов различных java.util.concurrent.atomic и sun.misc.Unsafe операций с полями объектов и элементами массива, стандартный набор барьерных операций для точного управления упорядочиванием памяти, а также стандартную reachability-fence операцию для обеспечения строгой доступности объекта.

  • JEP 269: удобные методы фабрики для коллекций [20] — определяет API библиотеки, чтобы упростить создание экземпляров коллекций и карт с небольшим количеством элементов. Статические методы фабрики в интерфейсах коллекции, которые создают компактные, неизменяемые экземпляры коллекции. Эти экземпляры по своей природе более эффективны. API создают коллекции, которые компактно представлены и не имеют класса-оболочки.

  • JEP 285: Подсказки по ожиданию с вращением [21] — предоставляет API, которая позволяет Java давать подсказки системе времени выполнения, что она находится в цикле спина. Некоторые аппаратные платформы выигрывают от программной индикации, указывающей на то, что поток находится в состоянии занятого ожидания.

  • JEP 321: HTTP-клиент (стандартный) [22]. Предоставляет новый API клиента HTTP, реализующий HTTP/2 и WebSocket, и может заменить устаревший API HttpURLConnection.

Ссылки

[1] Oracle Corporation, "Заметки о выпуске пакета средств разработки Java 9", (Online). Доступно: https://www.oracle.com/technetwork/java/javase/9u-relnotes-3704429.html. (Доступ к 13 ноября 2019 г.).

[2] Oracle Corporation, "Заметки о выпуске пакета средств разработки Java 10", (Online). Доступно: https://www.oracle.com/technetwork/java/javase/10u-relnotes-4108739.html. (Доступ к 13 ноября 2019 г.).

[3] Oracle Corporation, "Заметки о выпуске пакета средств разработки Java 11", (Online). Доступно: https://www.oracle.com/technetwork/java/javase/11u-relnotes-5093844.html. (Доступ к 13 ноября 2019 г.).

[4] Oracle Corporation, Project Jigsaw, 22 сентября 2017 года. (в Интернете). Доступно: http://openjdk.java.net/projects/jigsaw/. (Доступ к 13 ноября 2019 г.).

[5] Oracle Corporation, "JEP 328: Flight Recorder", 9 сентября 2018 года. (в Интернете). Доступно: http://openjdk.java.net/jeps/328. (Доступ к 13 ноября 2019 г.).

[6] Oracle Corporation, "Управление миссиями", 25 апреля 2019 года. (в Интернете). Доступно: https://wiki.openjdk.java.net/display/jmc/Main. (Доступ к 13 ноября 2019 г.).

[7] Oracle Corporation, "JEP 158: Unified JVM Logging", 14 февраля 2019 г. (в Интернете). Доступно: http://openjdk.java.net/jeps/158. (Доступ к 13 ноября 2019 г.).

[8] Oracle Corporation, "JEP 331: Профилирование кучи с низкими накладными расходами", 5 сентября 2018 года. (в Интернете). Доступно: http://openjdk.java.net/jeps/331. (Доступ к 13 ноября 2019 г.).

[9] Oracle Corporation, "JEP 259: Stack-Walking API", 18 июля 2017 г. (в Интернете). Доступно: http://openjdk.java.net/jeps/259. (Доступ к 13 ноября 2019 г.).

[10] Oracle Corporation, "JEP 248: Сделать G1 сборщик мусора по умолчанию", 12 сентября 2017 года. (в Интернете). Доступно: http://openjdk.java.net/jeps/248. (Доступ к 13 ноября 2019 г.).

[11] Oracle Corporation, "JEP 318: Epsilon: сборщик мусора без операций", 24 сентября 2018 года. (в Интернете). Доступно: http://openjdk.java.net/jeps/318. (Доступ к 13 ноября 2019 г.).

[12] Oracle Corporation, "JDK-8146115: улучшение обнаружения контейнеров Docker и использования конфигурации ресурсов", 16 сентября 2019 г. (в Интернете). Доступно: https://bugs.java.com/bugdatabase/view_bug.do?bug_id=JDK-8146115. (Доступ к 13 ноября 2019 г.).

[13] Oracle Corporation, "JEP 238: multi-release JAR Files", 22 июня 2017 года. (в Интернете). Доступно: http://openjdk.java.net/jeps/238. (Доступ к 13 ноября 2019 г.).

[14] Oracle Corporation, "JEP 197: сегментированные кэши кода", 28 апреля 2017 г. (в Интернете). Доступно: http://openjdk.java.net/jeps/197. (Доступ к 13 ноября 2019 г.).

[15] Oracle Corporation, "JEP 254: Compact Strings", 18 мая 2019 года. (в Интернете). Доступно: http://openjdk.java.net/jeps/254. (Доступ к 13 ноября 2019 г.).

[16] Oracle Corporation, JEP 310: Application Class-Data Sharing, 17 августа 2018 г. (в Интернете). Доступно: https://openjdk.java.net/jeps/310. (Доступ к 13 ноября 2019 г.).

[17] Oracle Corporation, "JEP 312: Thread-Local рукопожатия", 21 августа 2019 года. (в Интернете). Доступно: https://openjdk.java.net/jeps/312. (Доступ к 13 ноября 2019 г.).

[18] Oracle Corporation, "JDK-8198756: отложенное выделение потоков компилятора", 29 октября 2018 г. (в Интернете). Доступно: https://bugs.java.com/bugdatabase/view_bug.do?bug_id=8198756. (Доступ к 13 ноября 2019 г.).

[19] Oracle Corporation, "JEP 193: переменные-дескрипторы", 17 августа 2017 года. (в Интернете). Доступно: https://openjdk.java.net/jeps/193. (Доступ к 13 ноября 2019 г.).

[20] Oracle Corporation, "JEP 269: удобные методы фабрики для коллекций", 26 июня 2017 года. (в Интернете). Доступно: https://openjdk.java.net/jeps/269. (Доступ к 13 ноября 2019 г.).

[21] Oracle Corporation, "JEP 285: Spin-Wait Hints", 20 августа 2017 года. (в Интернете). Доступно: https://openjdk.java.net/jeps/285. (Доступ к 13 ноября 2019 г.).

[22] Oracle Corporation, "JEP 321: HTTP Client (Standard)," 27 сентября 2018 г. (в Интернете). Доступно: https://openjdk.java.net/jeps/321. (Доступ к 13 ноября 2019 г.).