如何把Java程序的启动速度加快100倍?GraalVM了解一下

在云原生时代,Java程序是有很大的劣势的,为什么这么说呢?你看Java的一个最简单的hello world都要大几十M的内存,启动也不不快。以最流行的spring boot/spring cloud微服务框架为例,启动一个已经优化好,很多bean需要lazy load的application至少需要3-4秒时间,内存需要几百M,业务逻辑稍微复杂一点点,没有1G以上的内存是很难满足业务的需要呢?

那么在云原生时代,Java会落后吗?答案到现在,笔者也不好说,不过大概率不会,为什么呢?因为java社区没有闲着,弄出来很多好玩的黑科技。下面我就一个充满黑科技的JVM介绍给大家,用他能帮助我们让Java程序的启动速度加快100倍,内存只需要原来的五分之一,甚至更少。

还等什么,让我们开始吧。

一、Graalvm的介绍

Graal VM是2018年Oracle开发的下一代JVM实现,被官方称为“Universal VM”和“Polyglot VM”,这是一个在HotSpot虚拟机基础上增强而成的跨语言全栈虚拟机,可以作为“任何语言”的运行平台使用,这里“任何语言”包括了Java、Scala、Groovy、Kotlin等基于Java虚拟机之上的语言,还包括了C、C++、Rust等基于LLVM的语言,同时支持其他像JavaScript、Ruby、Python和R语言等等。Graal VM可以无额外开销地混合使用这些编程语言,支持不同语言中混用对方的接口和对象,也能够支持这些语言使用已经编写好的本地库文件。

主要特性包括:

  • 高性能的现代Java
  • 占用资源少,启动速度快
  • JavaScript, Java, Ruby以及R混合编程
  • 在JVM上运行原生语言
  • 跨语言工具
  • JVM应用扩展
  • 原生应用扩展
  • 本地Java库
  • 数据库支持多语言
  • 创建自己的语言

二、Graalvm安装及环境配置

GraalVM包括社区版和企业版,我们以社区版为例,截取当前2020年6月份,最新的Release版本为:Graalvm Community 20.1.0,下载地址:https://www.graalvm.org/downloads/
不过社区版需要会让你跳转到github进行下载,github下载很慢,需要科学翻墙才行。

2.1 在Windows 10平台上安装

请按照以下步骤在x86 64位Windows上安装GraalVM Community Edition。

  1. GitHub上GraalVM Releases存储库。根据电脑配置,选择graalvm-ce-java8-windows-amd64-20.1.0.zipgraalvm-ce-java11-windows-amd64-20.1.0.zip并下载。

  2. 将文件压缩到文件系统,比如 d盘根目录。

  3. 配置JAVA_HOMEPATH环境变量。在Windows 7、8和10中,通过命令行设置环境变量的工作方式相同。

    • 将GraalVM bin文件夹添加到PATH环境变量:

      setx /M PATH "d:\graalvm-ce-java8-20.1.0\bin;%PATH%"
      
      
    • 设置JAVA_HOME环境变量以解析到GraalVM安装目录:

      setx /M JAVA_HOME "d:\graalvm-ce-java8-20.1.0"
      
      

      请注意/M,等同于的标志-m需要管理员权限的命令行。

  4. 重新启动命令提示符以重新加载环境变量。然后使用以下命令检查变量设置是否正确:

    echo %PATH%
    echo %JAVA_HOME%
    
    
    java -version
   openjdk version "1.8.0_252"
   OpenJDK Runtime Environment (build 1.8.0_252-b09)
   OpenJDK 64-Bit Server VM GraalVM CE 20.1.0 (build 25.252-b09-jvmci-20.1-b02, mixed mode)

2.2 使用gu工具安装 native image

要在GraalVM Community Edition中添加对Python,R,Ruby或WebAssembly语言解释器的支持,请使用功能[gu实用程序]GitHub上有一个由Oracle(gu available)维护的组件目录,您可以从中按名称安装组件:

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

要安装LLVM工具链组件,请运行:

gu install llvm-toolchain

要安装GraalVM本机映像,请运行:

gu install native-image

在Windows上使用native images的先决条件

要在Windows上使用本机映像,请遵循其他建议。所需的Microsoft Visual C ++(MSVC)版本取决于GraalVM所基于的JDK版本。对于基于JDK 8的GraalVM分发,您将需要MSVC 2010 SP1版本。推荐的安装方法是使用Microsoft Windows SDK 7.1:

  1. GRMSDKX_EN_DVD.isoMicrosoft下载SDK文件。
  2. 通过F:\Setup\SDKSetup.exe直接打开安装图像。

对于基于JDK 11的GraalVM分发,您将需要MSVC 2017 15.5.5或更高版本。

对于基于JDK 11和JDK 8的GraalVM发行版,共同的最后一个先决条件是适用于您的Visual Studio版本的正确的Developer Command Prompt。即,它应该是x64本机工具命令提示符。使用Visual Studio 2017或更高版本。

三、spring boot之Graalvm

其实在2019年spring 团队已经开始作手支持graalvm的native image功能。就在前几天(2020-6-10)spring-graalvm-native 发布了0.7.0版本。Spring团队承诺对Graal VM的支持必须在2020年10月之后才会正式提供,但现在的我们其实已经可以使用Graal VM来(实验性地)运行Spring、Spring Boot、Spring Data、Netty、JPA等等的一系列组件(不过SpringCloud中的组件暂时还不行)。
接下来,我们将尝试使用Graal VM来编译一个标准的Spring Boot应用。

3.1 准备工作

首先,我们先假设你准备编译的代码是“符合要求”的,即没有使用到Graal VM不支持的特性,譬如前面提到的Finalizer、CGLIB、InvokeDynamic这类功能。然后,由于我们用的是Graal VM的Java 8版本,也必须假设你编译使用Java语言级别在Java 8以内。
spring-graalvm-native的0.7版本基于刚刚发布的Spring Boot 2.3和上面提到的Graalvm 20.1.0 版本。请将你的pom.xml中的Spring Boot版本修改如下(假设你编译用的是Maven,用Gradle的请自行调整):

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.3.0</version>
    <relativePath/>
</parent> 

同时在pom.xml中增加spring对graalvm的支持(别忘了现在也添加Spring Milestones存储库,因为现在还没有通过Maven Central发行)。):

<dependencies>
        <dependency>
            <groupId>org.springframework.experimental</groupId>
            <artifactId>spring-graalvm-native</artifactId>
            <version>0.7.0</version>
        </dependency>
        ...
        <dependencies>
    <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>

由于GraalVM不支持GCLIB代理,因此Spring Boot需要使用JDK代理。因此,请使用proxyBeanMethods = false@SpringBootApplication类的属性:

@SpringBootApplication(proxyBeanMethods = false)
public class SpringBootHelloApplication {
    ...
}

3.2 开始native image成本地原生程序

现在,我们几乎已经准备好一切,最终可以运行native-image命令。这是一个示例,该示例基于提到的实现Reactive Spring Boot Web应用程序的示例项目。把java程序编译成本地程序,是一个很难一次性成功的事情,它取决于要编译为GraalVM本机映像的Spring Boot应用程序的类型!因此,最好的方法是从spring-graal-native项目的示例项目中获得一些参考和提示。

开始吧:

  1. 先maven编译,这部很简单,我们都很熟悉
mvn clean package
  1. 运行native image命令进行本地原生编译
native-image \
  -H:+TraceClassInitialization \
  -H:Name=spring-boot-graal
  -H:+ReportExceptionStackTraces \
  -Dspring.graal.remove-unused-autoconfig=true \
  -Dspring.graal.remove-yaml-support=true \
  -cp target/spring-boot-graal.jar

这个过程可能有点长,建议你起来喝杯水或者喝杯咖啡!这需要一些时间,具体取决于您的硬件!示例项目大约需要3-4分钟。如果一切顺利,您将在中找到本地编译的Spring Boot应用程序/target/spring-boot-graal。只需使用以下命令运行它:

./target/spring-boot-graal

=============================

© 版权声明
THE END
喜欢就支持一下吧
点赞8 分享
评论 抢沙发
头像
欢迎您留下宝贵的见解!
提交
头像

昵称

取消
昵称表情代码图片

    暂无评论内容