GraalVM系列Native Image Basics静态分析

 更新时间:2023年02月06日 16:29:07   作者:Hoeller  
这篇文章主要为大家介绍了GraalVM系列Native Image Basics静态分析详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪

引言

native image是GraalVM中提供的一个命令,可以把字节码文件或Jar包编译成为一个二进制可执行文件,同时它自己也是用Java语言开发的(实现了Java的语言自举)。

Build Time vs Run Time

native image在编译时,可能会执行类中的某些代码,比如给类中的static属性赋值(正常来说应该时运行时才去赋值的,现在是编译时可能就被赋值了,这里说的编译不是javac)。

通常,在Java中,一个类在第一次被使用时才会进行初始化,但是我们使用native image时就有可能直接进行类的初始化,我们把这个机制叫做build-time initialized,而二进制可执行文件在运行时,即便是第一次使用这个类时也都不会触发类的初始化了。

默认情况下native image是不会执行编译期类初始化的,我们可以通过两种方式来在编译时触发类的初始化:

  • 在执行native-image时传入--initialize-at-build-time=<class>
  • 在一个能编译时初始化的类中去使用其他的类

native image会把常用的JDK中的类在编译时进行初始化,比如java.lang.Stringjava.util.**,等等。

编译期类的初始化是一个专业特征,并不是所有类都适合。

请看下面的Demo加深理解:

public class HelloWorld {
    static class Greeter {
        static {
            System.out.println("Greeter is getting ready!");
        }
        public static void greet() {
          System.out.println("Hello, World!");
        }
    }
  public static void main(String[] args) {
    Greeter.greet();
  }
}

使用Java原本的方式编译并运行:

javac HelloWorld.java
java HelloWorld 
Greeter is getting ready!
Hello, World!

然后,我们把它编译为一个本地可执行文件,然后执行这个文件:

native-image HelloWorld
===============================================================
GraalVM Native Image: Generating 'helloworld' (executable)...
================================================================
...
Finished generating 'helloworld' in 14.9s.
./helloworld 
Greeter is getting ready!
Hello, World!

我们发现,上述两个过程都是在运行时才会对HelloWorld类进行初始化,所以默认情况下不会进行类的初始化。

我们通过添加--initialize-at-build-time=HelloWorld\$Greeter来看看编译期类初始化是怎样的:

native-image HelloWorld --initialize-at-build-time=HelloWorld\$Greeter
======================================================================
GraalVM Native Image: Generating 'helloworld' (executable)...
======================================================================
Greeter is getting ready!
...
Finished generating 'helloworld' in 13.6s.
./helloworld 
Hello, World!

我们发现Greeter is getting ready!是在编译时打印出来的,而真正在运行时由于HelloWorld类已经被初始化了,所以就没有再初始化了。而在编译时类初始化过程中被赋值的静态属性,会保存在二进制可执行文件中的image heap中。

Native Image Heap

Native Image heap也可以叫做image heap,它包含了:

  • 在编译时创建出来的对象
  • 在二进制文件中使用到的类对象(Class对象)
  • 嵌入在方法中的对象常量

可以通过编译时类初始化把一个对象放入image heap中:

class Example {
    private static final String message;
    static {
        message = System.getProperty("message");
    }
    public static void main(String[] args) {
        System.out.println("Hello, World! My message is: " + message);
    }
}

正常用java运行:

javac Example.java
java -Dmessage=hi Example
Hello, World! My message is: hi
java -Dmessage=hello Example 
Hello, World! My message is: hello
java Example
Hello, World! My message is: null

而如果使用编译期类初始化:

native-image Example --initialize-at-build-time=Example -Dmessage=native
========================================================================
GraalVM Native Image: Generating 'example' (executable)...
========================================================================
...
Finished generating 'example' in 19.0s.
./example 
Hello, World! My message is: native
./example -Dmessage=aNewMessage
Hello, World! My message is: native

Example类的初始化在编译期被执行了,并且会创建一个String对象赋值给message属性,并且把它存进了image heap中,运行的时候就直接从image heap中拿出来用了,忽略了运行时指定的-Dmessage

静态分析

native image在执行时,会先进行静态分析,静态分析会扫描出当前应用程序中真正用到了哪些类、方法、属性(其实通常我们一个应用中很多类,特别是依赖的第三方Jar包中的类,是没有被应用程序使用的),这些元素称之为reachable code

静态分析包含两个部分:

  • 扫描一个方法的字节码(比如main方法),找到它可达的其他元素
  • 从native image heap中的对象开始扫描,找到其他可达的元素

只有可达元素才能包含到二进制可执行文件中,一个二进制可执行文件编译出来后,运行过程中就不能再有新元素被添加进去了,比如动态类加载,我们把这个叫做closed-world。

官网原文  https://www.graalvm.org/latest/reference-manual/native-image/basics/

以上就是GraalVM系列Native Image Basics静态分析的详细内容,更多关于GraalVM Native Image Basics的资料请关注脚本之家其它相关文章!

相关文章

  • Java Feign微服务接口调用方法详细讲解

    Java Feign微服务接口调用方法详细讲解

    现如今微服务架构十分流行,而采用微服务构建系统也会带来更清晰的业务划分和可扩展性。java如果使用微服务就离不开springcloud,我这里是把服务注册到nacos上,各个服务之间的调用使用feign
    2023-01-01
  • Maven Plugin的@Mojo和@Execute的具体使用

    Maven Plugin的@Mojo和@Execute的具体使用

    本文主要介绍了Maven Plugin的@Mojo和@Execute的具体使用,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-09-09
  • Java计算两个程序运行时间的实例

    Java计算两个程序运行时间的实例

    下面小编就为大家带来一篇Java计算两个程序运行时间的实例。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-04-04
  • SpringBoot公共模块配置方式

    SpringBoot公共模块配置方式

    这篇文章主要介绍了SpringBoot公共模块配置方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2024-08-08
  • java的Guava工具包介绍

    java的Guava工具包介绍

    Java开发的同学应该都使用或者听说过Google提供的Guava工具包。日常使用最多的肯定是集合相关的工具类,还有Guava cache,除了这些之外Guava还提供了很多有用的功能,鉴于日常想用的时候找不到,这里就梳理一下Guava中那些好用的工具类,想优化代码的时候不妨过来看看
    2021-04-04
  • Java单线程程序实现实现简单聊天功能

    Java单线程程序实现实现简单聊天功能

    这篇文章主要介绍了Java单线程程序实现实现简单聊天功能,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-10-10
  • Java的项目构建工具Maven的配置和使用教程

    Java的项目构建工具Maven的配置和使用教程

    Maven是Java世界中的项目管理和构建自动化工具,基于POM项目对象模型的思想,下面我们就具体来看一下具体的Java的项目构建工具Maven的配置和使用教程:
    2016-05-05
  • SpringBoot过滤器与拦截器深入分析实现方法

    SpringBoot过滤器与拦截器深入分析实现方法

    大家应该都晓得实现过滤器需要实现 javax.servlet.Filter 接口,而拦截器会在处理指定请求之前和之后进行相关操作,配置拦截器需要两步,本文通过实例代码给大家介绍SpringBoot 过滤器和拦截器的相关知识,感兴趣的朋友一起看看吧
    2022-11-11
  • SpringBoot链路追踪skyworking的接入方法

    SpringBoot链路追踪skyworking的接入方法

    在SpringBoot项目中引入SkyWalking进行链路追踪,需要下载探针jar包,配置logback.xml,设置启动变量,以实现服务调用监控和错误预警,本文给大家介绍SpringBoot链路追踪skyworking的接入方法,感兴趣的朋友一起看看吧
    2024-10-10
  • mybatisPlus实现逻辑删除,自动生成创建时间和更新时间方式

    mybatisPlus实现逻辑删除,自动生成创建时间和更新时间方式

    MyBatisPlus框架中,通过@TableField(fill=FieldFill.INSERT)和@TableField(fill=FieldFill.UPDATE)注解可以实现在插入和更新时自动填充字段,比如创建时间和更新时间,使用@TableLogic注解标识逻辑删除字段
    2024-09-09

最新评论