GraalVM系列Native Image Basics静态分析
作者:Hoeller 发布时间:2023-08-08 03:05:38
引言
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.String
,java.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/
来源:https://juejin.cn/post/7196878348340248632


猜你喜欢
- DATAXDataX 是阿里巴巴集团内被广泛使用的离线数据同步工具/平台,实现包括 MySQL、Oracle、SqlServer、Postg
- C语言fchdir()函数:改变当前工作目录头文件:#include <unistd.h>定义函数:int fchdir(int
- 1.什么是灰度发布?灰度发布又称金丝雀发布,是在系统升级的时候能够平滑过渡的一种发布方式。在其上可以进行A/B测试,即让一部分用户继续用产品
- 我们经常会有这种场景,只需要把Spring Boot打成普通的jar包,不包含配置文件,供其他程序应用本文介绍如何使用Maven将Sprin
- 需求:有些时候,我们需要连接多个数据库,但是,在方法调用前并不知道到底是调用哪个。即同时保持多个数据库的连接,在方法中根据传入的参数来确定。
- Java 回调函数详解前言:C语言中回调函数解释:回调函数(Callback Function)是怎样一种函数呢?函数是用来被调用的,我们调
- 这篇会深化View拖拽实例,利用Flutter Animation、插值器以及AnimatedBuilder教大家实现带动画的抽屉效果。先来
- 1.相关概念Spring Boot 默认为我们提供了静态资源处理,使用 WebMvcAutoConfiguration 中的配置各种属性。建
- 摘要 &n
- #include<iostream>using namespace std;//非递归求解所有的子集void fun(int a
- Springmvc调用存储过程,并返回存储过程返还的数据java后端很多时候都需要和数据库进行交互,并返回业务数据。一般情况下都会采用执行S
- 1.前言在Mybatis中需要创建的配置文件有sqlMapconfig.xml,映射文件xxxMapper.xml,而这些文件在idea中并
- 在C#中,可以使用一些第三方库或内置类库实现动态执行脚本的功能。以下是几个常用的方案:1.使用Roslyn编译器Roslyn是微软推出的一个
- 一.前言这一篇来看看 SpringIOC 里面的一个细节点 , 来简单看看 BeanDefinition 这个对象 , 以及有没有办法对其进
- 崩溃来源使用过AIDL进行跨进程通信的同学,肯定遇到过DeadObjectException这个崩溃,那么这个崩溃是怎么来的,我们又该如何解
- 写项目时,要求仿微信朋友圈,双击顶栏置顶,于是封装了双击回调接口,方便大家拿来就用/** * Created by Administrato
- 其中定义WIFI AP的几个状态public static final int WIFI_AP_STATE_DISABLING = 10;
- logback自定义指定日志文件存储目录1、正常使用定义一个logback.xml配置文件即可:<?xml version="
- 前言我们从以下几个方面研究:SpringBoot的启动依赖启动器starter有什么作用启动引导类是怎么运行的内置的tomcat服务器原理p
- 有时候,我们需要将控件的背景颜色设定为透明,比如说label(标签)控件。那么,如何将控件的背景颜色设定为透明?是不是只要将控件的BackC