Уменьшение размера дистрибутива в Java 9

Через четыре месяца планируется выпустить Java 9 (надеемся, что переносов сроков больше не произойдёт). Ничто не мешает уже сейчас на предварительной версии проверить, насколько соответствует ожиданиям главная возможность новой версии — модульность (проект Jigsaw).

87ca6998f8304ae3b6c975dc4b8cbb33.png

В статье описываются изменения, требуемые для сборки дистрибутива с поддержкой модульности. Сборка дистрибутива производится в операционных системах Windows, macOS и Linux.

Полный список новых функций JDK 9 впечатляет. Проект Jigsaw является главной целью версии 9. Предметом данной статьи является составная часть проекта Jigsaw — JEP 275: Modular Java Application Packaging и связанные с ним

  • JEP 282: jlink: The Java Linker
  • JEP 220: Modular Run-Time Images
  • JEP 261: Module System
  • JEP 200: The Modular JDK

В JDK входит утилита командной строки Java Packager, позволяющая выполнять компиляцию, сборку, создание цифровой подписи и дистрибутивов Java-приложений. Функции, которые выполняет Java Packager, начиная с JDK 7 Update 6, доступны и в виде задач (tasks) для Ant. В официальной документации они имеют наименование JavaFX Ant Tasks, т.к. ранее предназначались в первую очередь для JavaFX-приложений.

JEP 275: Modular Java Application Packaging направлен на интеграцию модульности в Java Packager, в том числе для создания образа JRE, включающего только те модули, которые использует приложение. JavaFX Ant Tasks так же могут быть вызваны и из Maven, доминирующего на сегодня инструмента сборки, посредством Maven AntRun Plugin.

В экспериментах использовались:

  • операционные системы Windows 10, macOS Sierra 10.12.4, Ubuntu 16.04.2 LTS;
  • JDK 9 Early Access (Build 163 на момент написания статьи) для всех трёх операционных систем;
  • Apache Maven 3.3.9;
  • Inno Setup 5.5.9;
  • IDE с поддержкой Java 9 (например, IntelliJ IDEA 2017.1).

Код примера доступен на GitHub. Для компиляции и сборки дистрибутива используется Maven. Проект состоит из четырёх частей (модулей в терминологии Maven):
  • консольное (console) приложение без использования модулей (модулей Java 9);
  • консольное приложение с использованием модулей;
  • настольное (desktop) приложение без использования модулей;
  • настольное приложение с использованием модулей.

Сборка дистрибутивов выполняется во всех трёх операционных системах.

Сборка дистрибутива без использования модулей


Процесс сборки дистрибутива состоит из нескольких шагов:
  • компиляция и создание файла JAR;
  • формирование образа JRE;
  • создание дистрибутива, включающих JAR, образ JRE и вспомогательные исполняемые файлы для запуска.

Для создания дистрибутивов в macOS и Linux ничего дополнительно не нужно (кроме JDK и Maven). В операционной системе Windows предварительно необходимо установить Inno Setup или WiX Toolset. Далее подразумевается, что используется Inno Setup.

Создание файла JAR при использовании Maven проще выполнить обычным способом, т.е. используя Apache Maven JAR Plugin (другой способ — использование ). В манифесте (файле MANIFEST.MF) файла JAR, используемом для сборки дистрибутива немодульного (без использования модулей Java 9) приложения, обязательно должен быть указан Main-Class. По этой причине использование вышеуказанного плагина должно быть явно задано с указанием в конфигурации основного класса.

Описание использования задачи в файле pom.xml:

fb41236032144ae7a562d30338bbe7ea.png

Запуск компиляции и сборки дистрибутива в Windows и macOS:
mvn clean package -P native-deploy

Запуск компиляции и сборки дистрибутива в Linux (дополнительно создаётся файл архива tar.gz):
mvn clean package -P native-deploy,tar-gz

Файлы созданного дистрибутива с расширением exe, dmg располагаются в каталоге /target/deploy/native, с расширением tar.gz — в каталоге /target.

Добавление использования модулей


На этапе формирования образа JRE неявно будет задействован jlink, которому нужно передать информацию об используемых модулях.

Для определения, какие модули Java использует приложение, должна быть вручную запущена утилита jdeps. В версии 9 она дополнительно показывает используемые модули.

jdeps -s .jar

Первое приложение (console) использует единственный модуль java.base, второе (desktop) — модули java.base и java.desktop (вместе с транзитивными модулями, т.к. java.desktop сам зависит от других модулей).

Для первого приложения требуется добавить файл module-info.java, содержащий (указание базового модуля java.base необязательно):

module console.modular {
}

Файл module-info.java для второго приложения должен содержать:
module desktop.modular {
    requires java.desktop;
}

В файле pom.xml появляются обязательные параметры пути к файлам модулей (путь к стандартным модулям $JAVA_HOME/jmods указывать необязательно) и наименования модуля приложения. Включать в качестве ресурса JAR приложения становится излишним, т.к. он уже включён в виде модуля в образ JRE.

46f2cc0f5b64451dae74d41ffade8546.png

Запуск компиляции и сборки аналогичен ранее указанному.

Сравнение результатов


Размер в мегабайтах образа JRE в составе дистрибутива и собственно файла дистрибутива, созданных с использованием Java Packager:
Приложение Windows macOS Linux
образ JRE дистрибутив (exe) образ JRE дистрибутив (dmg) образ JRE дистрибутив (tar.gz)
console-nonmodular 165 36 181 69 204 72
desktop-nonmodular 165 36 181 69 204 72
console-modular 35 9 35 13 44 16
desktop-modular 72 18 75 29 85 31

Размер в мегабайтах образа JRE, созданного при ручном запуске jlink с наиболее оптимальным набором параметров (недоступном из Java Packager):
jlink --module-path  --add-modules  --output  --compress=2 --no-header-files --no-man-pages --strip-debug

Приложение Windows, образ JRE macOS, образ JRE Linux, образ JRE
console-modular 22 21 29
desktop-modular 38 39 49

Сильнее всего размер образа JRE уменьшился на macOS:
  • на 81% скриптом сборки при использовании Java Packager;
  • на 88% при использовании jlink.

Выводы


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

На проходящих 4 апреля (JBreak 2017 в Новосибирске) и 7–8 апреля (JPoint 2017 в Москве) конференциях можно будет послушать доклады о других интересных возможностях Java 9 и следующих версий Java:

  • Functional Reactive with Core Java9 (Sven Ruppert)
  • Going Native: Foreign Functions on the JVM (Charles Nutter)
  • Техники векторизации кода в JVM (Владимир Иванов)
  • Повесть о том, как один инженер HTTP/2 Client разгонял (Сергей Куксенко)
  • Java 9 Модули. Почему не OSGi? (Никита Липский)
  • «Преждевременная» компиляция — это нормально? (Дмитрий Чуйко)
  • Java Puzzlers NG S02: Всё чудесатее и чудесатее (Тагир Валеев, Барух Садогурский)

Комментарии (0)

© Habrahabr.ru