Компилируйте Java-программы в собственный машинный код с помощью GraalVM!

Java

публика

Заметки по кодированию, побитовые записи, будущие статьи так же будут синхронизированы с официальным аккаунтом (Coding Insight), надеюсь все обратят внимание ^_^

предисловие

Адрес гитхаба:LjyYano/Thinking_in_Java_MindMapping

В апреле 2018 года Oracle Labs анонсировала новую черную технологию:Graal VM.

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

Информации о Graal VM в Интернете сейчас не так много, но вам все же нужно посмотреть официальную документацию. Эта статья призвана кратко представить:

  • Что такое Graal VM?
  • Каковы преимущества Graal VM?
  • Каковы недостатки Graal VM?
  • Как работает Graal VM?
  • Установите виртуальную машину Graal на macOS
  • Скомпилируйте Java-приложение на основе Spring Boot в本地应用程序

карта разума

Ниже приведен краткий обзор Graal VM.思维导图.

Легкая для понимания статья:GraalVM: Java в эпоху микросервисов.

Что такое GraalVM

Graal VM, официально известная как «Universal VM» и «Polyglot VM», представляет собой кросс-языковую виртуальную машину с полным стеком, улучшенную на основе виртуальной машины HotSpot под слоганом «Запускайте программы быстрее в любом месте». Вы можете запустить «любой язык» на виртуальной машине Graal, в том числе:

  • Языки на базе виртуальной машины Java: Java, Scala, Groovy, Kotlin и др.;
  • Языки на базе LLVM: C, C++, Rust;
  • Другие языки: JavaScript, Ruby, Python, R и т. д.

Graal VM может смешивать эти языки программирования без дополнительных накладных расходов, поддерживать смешивание интерфейсов и объектов друг друга на разных языках, а также поддерживать использование нативных библиотек, написанных на этих языках.

Преимущества GraalVM

Подробности смотрите в официальной документации:Почему GraalVM?

Я думаю, что самая важная особенностьAhead-of-Time Compilation. Substrate VM — это очень маленькая среда выполнения в Graal VM версии 0.20, включая независимую обработку исключений, планирование синхронизации, управление потоками, управление памятью (сборку мусора) и компоненты доступа JNI. Substrate VM также включает в себя本地镜像的构造器(Native Image Generator), пользователи могут создавать исполняемые файлы на основе сборочной машины через локальный конструктор образов.

Конструктор использует технологию Points-To Analysis для поиска всех доступных кодов из записи программы, предоставленной пользователем. Во время поиска он также выполнит код инициализации и сохранит инициализированную кучу в моментальный снимок кучи, когда исполняемый файл будет окончательно сгенерирован.

Substrate VM может запускаться непосредственно из целевой программы, не повторяя процесс инициализации виртуальной машины Java. Но, соответственно, также в принципе определено, что Substrate VM должна требовать, чтобы целевая программа была полностью закрыта, то есть другой независимый от времени компиляции код и библиотеки классов не могли быть динамически загружены. Основываясь на этом предположении, Substrate VM может исследовать все пространство компиляции и определить целевой метод для всех вызовов виртуальных методов с помощью статического анализа.

Адаптация Java к Native

Если раньше для одного сервиса требовалось 7*24 часа бесперебойной работы и высокая доступность одной машины, то в настоящее время очень подходят Java-сервисы. Но все Java-приложения должны работать на сотнях мегабайт JRE, что не подходит для микросервисов.

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

Предварительная компиляция GraalVM дает решение: официально после использования GraalVm время запуска может быть увеличено в 50 раз, а память уменьшена в 5 раз.

Недостатки Graal VM

Язык Java изначально ущемлен в микросервисах, потому что Java родился под лозунгом «напиши один раз, работай где угодно». Этот слоган встроен в ДНК Java. Если вы захотите их изменить (на самом деле сравните недостатки Java с преимуществами других языков), возникнет много трудностей:

  • Механизм отражения языка Java затрудняет создание исполняемых файлов во время компиляции. Поскольку интерфейс API можно вызывать динамически во время выполнения с помощью механизма отражения, они не воспринимаются во время компиляции. Если механизм отражения не будет отменен или не будет предоставлен файл конфигурации для вызова отражения во время компиляции.
  • Библиотеки байт-кода ASM, CGLIB и Javassist будут генерировать и изменять байт-коды во время выполнения, которые нельзя скомпилировать в машинный код через AOT. Например, внедрение зависимостей Spring использует расширение CGLIB. Spring адаптировал GraalVM в новой версии и может закрыть CGLIB.
  • Откажитесь от внутреннего заимствования самой HotSpot VM, потому что в локальном зеркале затирается даже сам HotSpot.
  • Время запуска и использование памяти действительно значительно оптимизированы, но для крупномасштабных приложений, которые работают в течение длительного времени, может не быть быстрого приложения HotSpot Java.

Как работает Graal VM

Основной принцип работы Graal VM заключается в преобразовании исходного кода этих языков (например, JavaScript) или скомпилированного промежуточного формата исходного кода (например, байт-кода LLVM) в промежуточное представление (Intermediate Representation, IR), которое можно принимается Graal VM через интерпретатор. ), например, разработка интерпретатора для преобразования байт-кода, выводимого LLVM, для поддержки языков C и C ++. Этот процесс называется «специализацией программы» (специализированная, также часто называемая частичной оценкой).

Graal VM предоставляет набор инструментов Truffle для быстрого создания интерпретатора для нового языка и использует его для создания высокопроизводительного интерпретатора байт-кода LLVM под названием Sulong.

Установите виртуальную машину Graal на macOS

Другие платформы, такие как Linux и Windows, могут относиться кInstall GraalVM. Поскольку я использую macOS, в этой статье описывается, как установить Graal VM, GraalVM Community Edition на основе OpenJDK 11 на macOS.

Установить виртуальную машину Graal

GraalVM Community Edition в macOS представляет собой файл tar.gz, а каталог установки JDK:

/Library/Java/JavaVirtualMachines/<graalvm>/Contents/Home

Шаги установки для 64-разрядной версии macOS x86 следующие:

  1. существуетGraalVM Releases repository on GitHubнайти наgraalvm-ce-java11-darwin-amd64-20.1.0.tar.gzскачать.
  2. распаковать
tar -xvf graalvm-ce-java11-darwin-amd64-20.1.0.tar.gz
  1. переместить папку в/Library/Java/JavaVirtualMachinesкаталог (требуется sudo).
sudo mv graalvm-ce-java11-20.1.0 /Library/Java/JavaVirtualMachines

Чтобы проверить, прошла ли установка успешно, вы можете запустить команду:

/usr/libexec/java_home -V

Текущий результат:

Matching Java Virtual Machines (2):
    11.0.7, x86_64:	"GraalVM CE 20.1.0"	/Library/Java/JavaVirtualMachines/graalvm-ce-java11-20.1.0/Contents/Home
    1.8.0_201, x86_64:	"Java SE 8"	/Library/Java/JavaVirtualMachines/jdk1.8.0_201.jdk/Contents/Home

/Library/Java/JavaVirtualMachines/graalvm-ce-java11-20.1.0/Contents/Home
  1. Поскольку на машине может быть несколько JDK, необходимо настроить среду выполнения.

Поставить GraalVMbinприсоединение к каталогуPATHпеременные окружения.

export PATH=/Library/Java/JavaVirtualMachines/graalvm-ce-java11-20.1.0/Contents/Home/bin:$PATH

настраиватьJAVA_HOMEпеременные окружения.

export JAVA_HOME=/Library/Java/JavaVirtualMachines/graalvm-ce-java11-20.1.0/Contents/Home

Примечание. Возможно, потребуется изменить файл конфигурации bashc.

Установите компоненты GraalVM

Благодаря вышеперечисленным шагам основные компоненты GraalVM были установлены.Если вам нужна дополнительная поддержка таких языков, как Python и R, вам нужно использоватьguкомпоненты.

gu install ruby
gu install r
gu install python
gu install wasm

УстановитьGraalVM Native Image, выполните команду:

gu install native-image

УстановитьLLVM toolchainкомпонент, выполните команду:

gu install llvm-toolchain

Скомпилируйте Java-приложение на основе Spring Boot в собственное приложение.

Вы можете обратиться к GitHubspring-boot-graalvmПроект, в котором перечислены все проблемы, которые могут возникнуть, когда GraalVM подробно компилирует Java-приложения Spring Boot, и сравнивается запуск и компиляция Java-приложений с локально исполняемыми Java-программами.

Проект Spring Graal Native, совместно поддерживаемый Spring и Graal VM, уже предоставляет информацию о конфигурации для большинства компонентов Spring Boot (и некоторых исправлений, которые необходимо обрабатывать на уровне кода), и нам нужно просто полагаться на этот проект. Таким образом, Graal VM может получить конфигурацию отражения, динамического прокси и т. д. во время компиляции. Нам нужно только просто зависеть от проекта.

Нужно добавить зависимости в pom.xml:

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context-indexer</artifactId>
    <optional>true</optional>
</dependency>
<dependency>
    <groupId>org.springframework.experimental</groupId>
    <artifactId>spring-graalvm-native</artifactId>
    <version>0.7.1</version>
</dependency>

Указываем путь к классу запуска:

<properties>
    <start-class>com.yano.workflow.WorkflowApplication</start-class>
</properties>

Настройте отдельный профиль, который передается во время компиляцииnative-image-maven-pluginПлагин компилирует его в собственный исполняемый файл.

<profiles>
    <profile>
        <id>native</id>
        <build>
            <plugins>
                <plugin>
                    <groupId>org.graalvm.nativeimage</groupId>
                    <artifactId>native-image-maven-plugin</artifactId>
                    <version>20.1.0</version>
                    <configuration>
                        <buildArgs>-J-Xmx4G -H:+TraceClassInitialization
                            -H:+ReportExceptionStackTraces
                            -Dspring.graal.remove-unused-autoconfig=true
                            -Dspring.graal.remove-yaml-support=true
                        </buildArgs>
                        <imageName>${project.artifactId}</imageName>
                    </configuration>
                    <executions>
                        <execution>
                            <goals>
                                <goal>native-image</goal>
                            </goals>
                            <phase>package</phase>
                        </execution>
                    </executions>
                </plugin>
                <plugin>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-maven-plugin</artifactId>
                </plugin>
            </plugins>
        </build>
    </profile>
</profiles>

Плагин отсутствует в центральном репозитории Maven, нужно указать pluginRepositories и репозитории:

<repositories>
    <repository>
        <id>spring-milestones</id>
        <name>Spring Milestones</name>
        <url>https://repo.spring.io/milestone</url>
    </repository>
</repositories>
<pluginRepositories>
    <pluginRepository>
        <id>spring-milestones</id>
        <name>Spring Milestones</name>
        <url>https://repo.spring.io/milestone</url>
    </pluginRepository>
</pluginRepositories>

Graal VM не поддерживает CGLIB и может использовать только динамический прокси-сервер JDK, поэтому расширение bean-компонента Spring для общих классов следует отключить. Версия Spring Boot должна быть больше или равна 2.2,SpringBootApplicationУстановите для параметра proxyBeanMethods значение false в аннотации.

@SpringBootApplication(proxyBeanMethods = false)
public class SpringBootHelloApplication {

	public static void main(String[] args) {
		SpringApplication.run(SpringBootHelloApplication.class, args);
	}

}

Упакуйте проект через maven в командной строке:

mvn -Pnative clean package

Наконец, исполняемый файл можно увидеть в целевом каталоге, который составляет около 50 МБ по сравнению с 17 МБ для толстой банки.

java -jar target/spring-boot-graal-0.0.1-SNAPSHOT.jar

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::             (v2.3.0.M4)

2020-04-30 15:40:21.187  INFO 40149 --- [           main] i.j.s.SpringBootHelloApplication         : Starting SpringBootHelloApplication v0.0.1-SNAPSHOT on PikeBook.fritz.box with PID 40149 (/Users/jonashecht/dev/spring-boot/spring-boot-graalvm/target/spring-boot-graal-0.0.1-SNAPSHOT.jar started by jonashecht in /Users/jonashecht/dev/spring-boot/spring-boot-graalvm)
2020-04-30 15:40:21.190  INFO 40149 --- [           main] i.j.s.SpringBootHelloApplication         : No active profile set, falling back to default profiles: default
2020-04-30 15:40:22.280  INFO 40149 --- [           main] o.s.b.web.embedded.netty.NettyWebServer  : Netty started on port(s): 8080
2020-04-30 15:40:22.288  INFO 40149 --- [           main] i.j.s.SpringBootHelloApplication         : Started SpringBootHelloApplication in 1.47 seconds (JVM running for 1.924)

Может запускать программу прямо через командную строку, скорость запуска очень высокая. По сравнению с обычным веб-приложением Hello World время запуска составляет1.47s,используется внутренняя память491 MB.

Для программ Spring Boot, скомпилированных в собственный код, скорость запуска составляет0.078s,используется внутренняя память30 MB.

./spring-boot-graal

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::

2020-05-01 10:25:31.200  INFO 42231 --- [           main] i.j.s.SpringBootHelloApplication         : Starting SpringBootHelloApplication on PikeBook.fritz.box with PID 42231 (/Users/jonashecht/dev/spring-boot/spring-boot-graalvm/target/native-image/spring-boot-graal started by jonashecht in /Users/jonashecht/dev/spring-boot/spring-boot-graalvm/target/native-image)
2020-05-01 10:25:31.200  INFO 42231 --- [           main] i.j.s.SpringBootHelloApplication         : No active profile set, falling back to default profiles: default
2020-05-01 10:25:31.241  WARN 42231 --- [           main] io.netty.channel.DefaultChannelId        : Failed to find the current process ID from ''; using a random value: 635087100
2020-05-01 10:25:31.245  INFO 42231 --- [           main] o.s.b.web.embedded.netty.NettyWebServer  : Netty started on port(s): 8080
2020-05-01 10:25:31.245  INFO 42231 --- [           main] i.j.s.SpringBootHelloApplication         : Started SpringBootHelloApplication in 0.078 seconds (JVM running for 0.08)

Суммировать

  • В этой статье в основном обсуждается взаимосвязь между GraalVM и Java.На GraalVM можно запускать многие языки.Пожалуйста, обратитесь кWhy GraalVM.
  • Обратите внимание на конфигурацию переменной среды Graal, если конфигурация неверна, она не может быть скомпилирована, в то же время для JDK 11 требуется более высокая версия maven.
  • Graal VM и GraalVM — это одно и то же, официальный сайт называется GraalVM, а в других местах — Graal VM...
  • Чтобы адаптироваться к нативу, развивается и сам JDK.
  • Собственное приложение Java, скомпилированное GraalVM, подходит только для одноразового запуска, краткосрочных сценариев, длительных или традиционных программ Java более эффективны.
  • Адрес GitHub для этой статьи:LjyYano/Thinking_in_Java_MindMapping

публика

Заметки по кодированию, побитовые записи, будущие статьи так же будут синхронизированы с официальным аккаунтом (Coding Insight), надеюсь все обратят внимание ^_^