「JVM 编译优化」提前编译器
1996 年 JDK 1.0 发布,同年 7 月 外挂即时编译器发布(JDK 1.0.2),而 Java 提前编译发布在之后几个月(IBM High Performance Compiler for Java),1998 年 GNU 组织公布 GCC 家族新成员 GNU Compiler for Java(GCJ,2018 年从 GCC 家族除名),在 OpenJDK 流行起来之前,GCJ 是 Linux 发行版自带的 Java 实现版本;
AOT Compiler 因丢失了平台中立性而在 Java 世界沉寂长达 15 年;至 2013 年,因 Android 提前编译的 ART(Andriod Runtime)蹂躏式的取代即时编译的 Dalvik VM(Andriod 4.4),大大震撼了 Java 世界,Java AOT Compiler 重新被翻了出来;
提前编译就是以平台中立性、字节膨胀(提前编译的本地二进制体积明显大于字节码体积)、动态扩展(提前编译要求程序封闭,不能外部动态加载新的字节码)等特性换取足够好的性能;
文章目录
- 1. 提前编译的优缺点
 - 2. Jaotc 提前编译
 
1. 提前编译的优缺点
提前编译的两种方案
方案一,在程序运行之前把程序代码编译成机器码的静态翻译(类似传统 C、C++ 编译器,Substrate VM);- 优势在于,提前编译可以放心大胆的采用
全程序优化措施以获取更好的运行时性能;即时编译所消耗的时间和资源是原本可以用来运行程序的时间,这导致即使编译不得不放松一些全程序分析(Inter-Procedural Analysis,IPA,或称过程间分析;如分析变量的值是否一定为常量、代码块是否永远不会被执行,虚方法的调用是否只会存在一个版本,这些分析对流敏感、对路径敏感、对上下文敏感、对字段敏感,需要大量计算工作;目前 JVM 大多使用方法内联达到过程内分析的效果,或借助假设激进优化,不求精确结果); 
- 优势在于,提前编译可以放心大胆的采用
 方案二,将原本即时编译器运行时编译要做的事提前做好并保存下来,下次运行到这些代码时直接加载并运行(如公共库代码在同一机器被多个 Java 进程使用);(Jaotc);- 相当于给即时编译做缓存加速,又称动态提前编译(Dynamic AOT)或即时编译缓存(JIT Caching),已被主流商用 JDK 完全支持(CDS,Class Data Sharing,编译质量低于即时编译);基于 Graal 编译器实现的 Jaotc 提前编译器会针对目标机器为应用程序做较高质量优化的提前编译,然后 HotSpot 在运行时可以直接加载运行(快启动、快响应);
 
即时编译的优势
- 性能分析制导优化(Profile-Guided Optimization,PGO),即时编译会在解释器或客户端编译器运行过程中收集性能监控信息,从而做出明显偏好性资源分配(如抽象类的实际类型、判断条件走哪个分支、方法调用的实际版本、循环会走多少次等,在静态分析中是无法得到或无法唯一确认的,通过这些可以实现集中优化和偏好资源分配,如分支预测、寄存器、缓存等资源);
 - 激进预测性优化(Aggressive Speculative Optimization),静态优化必须保证优化前后执行结果等效;而即时编译可以不那么保守,只要监控信息支持,它可以大胆执行预测性的优化,从而大幅度降低目标代码复杂度、提升运行速度;
 - 链接时优化(Link-Time Optimization,LTO),提前编译的主程序与动态链接库的代码在他们编译时完全独立,两者各自编译、优化,存在明显的边界隔阂(比如方法内联会很困难);而即时编译在对 Class 文件做优化时是基于程序整体的;
 
2. Jaotc 提前编译
Jaotc 支持对 Class 文件和模块进行提前编译,但这些功能必须针对特定物理机器和目标 VM Arguments;
HelloWorld 提前编译演示
# 前端编译,生成 HelloWorld.class
$ javac HelloWorld.java
# 直接通过 HelloWorld.class 运行
$ java HelloWorld# 提前编译 HelloWorld.class
$ jaotc --output libHelloWorld.so HelloWorld.class# 确认 libHelloWorld.so 是否一个静态链接库
$ ldd libHelloWorld.so
statically linked# 查看 HelloWorld 的构造函数和 main 方法
$ nm libHelloWorld.so
...
0000000000002a20 t HelloWorld.()V
0000000000002b20 t HelloWorld.main([Ljava/lang/String;)V
...# 通过静态链接库(而非 HelloWorld.class)运行
java -XX:AOTLibrary=./libHelloWorld.so HelloWorld
 
java.base 模块提前编译演示
- java.base-list.txt(排除无法提前编译的类);
 
# jaotc: java.lang.StackOverflowError
exclude sun.util.resources.LocaleNames.getContents()[[Ljava/lang/Object;
exclude sun.util.resources.TimeZoneNames.getContents()[[Ljava/lang/Object;
exclude sun.util.resources.cldr.LocaleNames.getContents()[[Ljava/lang/Object;
exclude sun.util.resources..*.LocaleNames_.*.getContents\(\)\[\[Ljava/lang/Object;
exclude sun.util.resources..*.LocaleNames_.*_.*.getContents\(\)\[\[Ljava/lang/Object;
exclude sun.util.resources..*.TimeZoneNames_.*.getContents\(\)\[\[Ljava/lang/Object;
exclude sun.util.resources..*.TimeZoneNames_.*_.*.getContents\(\)\[\[Ljava/lang/Object;
# java.lang.Error: Trampoline must not be defined by the bootstrap classloader
exclude sun.reflect.misc.Trampoline.<clinit>()V
exclude sun.reflect.misc.Trampoline.invoke(Ljava/lang/reflect/Method;Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;
# JVM asserts
exclude com.sun.crypto.provider.AESWrapCipher.engineUnwrap([BLjava/lang/String;I)Ljava/security/Key;
exclude sun.security.ssl.*
exclude sun.net.RegisteredDomain.<clinit>()V
# Huge methods
exclude jdk.internal.module.SystemModules.descriptors()[Ljava/lang/module/ModuleDescriptor;
 
# -J 参数传递与目标 VM Arguments 相关的运行时参数;
$ jaotc -J-XX:+UseCompressedOops -J-XX:+UseG1GC -J-Xmx4g --compile-for-tiered --info --compile-commands java.base-list.txt --output libjava.base-coop.so --module java.base
Compiling libjava.base-coop.so...
6177 classes found (335 ms)
55845 methods total, 49575 methods to compile (1037 ms)
Compiling with 4 threads
......
49575 methods compiled, 0 methods failed (138821 ms)
Parsing compiled code (906 ms)
Processing metadata (10867 ms)
Preparing stubs binary (0 ms)
Preparing compiled binary (103 ms)
Creating binary: libjava.base-coop.o (2719 ms)
Creating shared library: libjava.base-coop.so (5812 ms)
Total time: 163609 ms# 用 -XX:AOTLibrary 指定链接库位置,运行 HelloWorld
$ java -XX:AOTLibrary=java_base/libjava.base-coop.so, ./libHelloWorld.so HelloWorld
Hello World!# 用 -XX:+PrintAOT 打印使用了提前编译的方法
$ java -XX:+PrintAOT -XX:AOTLibrary=./libHelloWorld.so HelloWorld11  1   loaded  ./libHelloWorld.so aot library105 1   aot[ 1] HelloWorld.()V105 2   aot[ 1] HelloWorld.main([Ljava/lang/String;)V
Hello World!
 
Jaotc 还难以直接编译 SpringBoot、MyBatis 等常见的第三方库,Java 标准库也只能比较顺利的编译 java.base 模块;Graal 编译器也无法支持 ZGC 与 Shenandoah GC,只能支持 G1 和 Parallel(PS + PS Old);未来很长时间 Java 后端编译的主角应该还是即时编译;
上一篇:「JVM 编译优化」即时编译器
PS:感谢每一位志同道合者的阅读,欢迎关注、评论、赞!
参考资料:
- [1]《深入理解 Java 虚拟机》
 
相关文章:
「JVM 编译优化」提前编译器
1996 年 JDK 1.0 发布,同年 7 月 外挂即时编译器发布(JDK 1.0.2),而 Java 提前编译发布在之后几个月(IBM High Performance Compiler for Java),1998 年 GNU 组织公布 GCC 家族新成员 GNU Compi…...
Golang channel 用法与实现原理
文章目录1.简介2.用法3.三种状态4.实现原理数据结构原理概述5.小结参考文献1.简介 Golang channel 是一种并发原语,用于在不同 goroutine 之间进行通信和同步。本质上,channel 是一种类型安全的 FIFO 队列,它可以实现多个 goroutine 之间的同…...
jackson 序列化、反序列化的时候第一个大写单词变成小写了(属性设置不成功)
参考链接:https://www.baeldung.com/jackson-annotations 遇到的问题 之前和第三方对接,返回的接口中的属性名称是拼音字母大写,奇怪,反序列化的时候好多字段都为空,没设置进去。 因为对接前,我先用 IntelliJ IDEA …...
如何判断机器学习数据集是否是线性的
首先,线性和非线性函数之间的区别: 左边是线性函数,右边是非线性函数。 线性函数:可以简单定义为始终遵循以下原则的函数: 输入/输出=常数。 线性方程总是1次多项式(例如x+2y+3=0)。在二维情况下,它们总是形成直线;在其他维度中,它们也可以形成平面、点或超平面。它们的…...
后端基础SQL
SQL基础语法: sql对大小写不敏感,eg: SELECT 等效于 select;select: select用于从表中查找数据,select 列名 from 表名 —> 结果集::仅有查询列的结果表; SELECT * FROM 表名称 ----> 结果集: 查找表的所有数据…...
Ubuntu 18.04 上编译和安装内核(内核源码版本)
Ubuntu 18.04 上编译和安装内核(内核源码版本) linux发行版本为,ubuntu18.04。内核版本为5.15.7。其他版本类似。 1.下载内核源代码。可以从官方网站下载最新的内核源代码,也可以使用 Git 命令从 Linux 内核的 Git 仓库中获取最新…...
day 53|● 1143.最长公共子序列 ● 1035.不相交的线 ● 53. 最大子序和 动态规划
1143. 最长公共子序列 给定两个字符串 text1 和 text2,返回这两个字符串的最长 公共子序列 的长度。如果不存在 公共子序列 ,返回 0 。 一个字符串的 子序列 是指这样一个新的字符串:它是由原字符串在不改变字符的相对顺序的情况下删除某些…...
运维工程师必知的十项Linux常识
1、GNU和GPL GNU计划(又称革奴计划),是由Richard Stallman(理查德斯托曼)在1983年9月27日公开发起的软件集体协作计划。它的目标是创建一套完全的操作系统。GNU也称为软件工程项目。GPL是GNU的通用公共许可证…...
C++ 11 之右值引用和移动语义
文章目录左值引用与右值引用1、左值与右值2、纯右值、将亡值3、左值引用与右值引用4、右值引用和 std::move 使用场景引用限定符移动语义—std::move()完美转发emplace_back 减少内存拷贝和移动总结c11中引用了右值引用和移动语义,可以避免无谓的复制,提…...
【第一章:Spring概述、特点、IOC容器、IOC操作bean管理(基于xml方式)】
第一章:Spring概述、特点、IOC容器、IOC操作bean管理(基于xml方式) 1.Spring是什么? ①Spring是一款主流的java EE 轻量级开源框架。 ②广义的Spring:Spring技术栈,Spring不再是一个单纯的应用框架&#x…...
CSS变量
前端的开发工作中,CSS 是不可或缺的部分;实际工作中,我们通过JavaScript 来进行数据和交互工作,CSS 为用户呈现可视化的界面。有时,CSS 来进行部分交互效果是不是会比 JavaScript 更高效、更省事呢? 一、变…...
.net7窗口编程c#2022实战(1)-zip压缩精灵(1)
目录 创建ZIP精灵项目拖控件OpenFileDialog 类压缩与解压缩编写我们自己的代码其它参考内容创建ZIP精灵项目 VS2022中新建项目。 为窗体取一个标题名称 拖控件 左边工具栏里选择控件 拖三个按钮控件和一个listbox控件...
云计算|OpenStack|使用VMware安装华为云的R006版CNA和VRM
前言: FusionCompute架构 (CNA、VRM) CNA(ComputingNode Agent):计算节点代理VNA虚拟节点代理,部署在CNA上,实施计算、存储、网络的虚拟化的配置管理。VRM(Virtual Resource Manager):虚拟资源管理器 VNA可以省略不安装 本次实验使用的是V…...
中央一号文件首提“即时零售”,县域掀起消费业态新风潮
经过几年的探索,即时零售已经逐步走向成熟,并开始向三四线城市以及乡镇城市渗透。 过去一年,京东、美团、阿里争先布局即时零售市场,完善即时配送网络、培养用户消费习惯,即时零售订单迎来了骤增。2022年下半年&#…...
python多线程编程
Python多线程编程中常用方法: 1、join()方法:如果一个线程或者在函数执行的过程中调用另一个线程,并且希望待其完成操作后才能执行,那么在调用线程的时就可以使用被调线程的join方法join([timeout]) timeout:可选参数…...
小熊电器:精品与创意,走上“顶流之路”的两把“宝剑”
回顾2022年,小家电市场降温趋势明显,业绩表现整体低迷,如主打高端路线的北鼎,去年8亿元的营收出现个位数下滑,归母净利润同比下降超56%;苏泊尔营收也出现微降,归母净利润预计同比增长不到10%。而…...
如何描述元素与元素间的逻辑关系?
逻辑结构反映的是数据元素之间的关系,它们与数据元素在计算机中的存储位置无关,是数据结构在用户面前所呈现的形式。根据不同的逻辑结构来分,数据结构可分为集合、线性结构、树形结构和图形结构4种形式,接下来分别进行简要介绍。 …...
【3】linux命令每日分享——mv改名或移动
大家好,这里是sdust-vrlab,Linux是一种免费使用和自由传播的类UNIX操作系统,Linux的基本思想有两点:一切都是文件;每个文件都有确定的用途;linux涉及到IT行业的方方面面,在我们日常的学习中&…...
【2023最火教程】Python性能测试框架Locust实战教程(建议收藏)
01、认识Locust Locust是一个比较容易上手的分布式用户负载测试工具。它旨在对网站(或其他系统)进行负载测试,并确定系统可以处理多少个并发用户,Locust 在英文中是 蝗虫 的意思:作者的想法是在测试期间,放…...
深入浅出C++ ——手撕AVL树
文章目录前言一、AVL 树介绍二、AVL树节点的定义三、AVL树的插入四、AVL树的旋转五、AVL树的验证六、AVL树的删除七、AVL树的性能八、AVL树的实现前言 在前面的文章中介绍了map / multimap / set / multiset 容器,这几个容器的底层都是按照二叉搜索树来实现的。但是…...
微信小程序之bind和catch
这两个呢,都是绑定事件用的,具体使用有些小区别。 官方文档: 事件冒泡处理不同 bind:绑定的事件会向上冒泡,即触发当前组件的事件后,还会继续触发父组件的相同事件。例如,有一个子视图绑定了b…...
椭圆曲线密码学(ECC)
一、ECC算法概述 椭圆曲线密码学(Elliptic Curve Cryptography)是基于椭圆曲线数学理论的公钥密码系统,由Neal Koblitz和Victor Miller在1985年独立提出。相比RSA,ECC在相同安全强度下密钥更短(256位ECC ≈ 3072位RSA…...
vscode(仍待补充)
写于2025 6.9 主包将加入vscode这个更权威的圈子 vscode的基本使用 侧边栏 vscode还能连接ssh? debug时使用的launch文件 1.task.json {"tasks": [{"type": "cppbuild","label": "C/C: gcc.exe 生成活动文件"…...
解决Ubuntu22.04 VMware失败的问题 ubuntu入门之二十八
现象1 打开VMware失败 Ubuntu升级之后打开VMware上报需要安装vmmon和vmnet,点击确认后如下提示 最终上报fail 解决方法 内核升级导致,需要在新内核下重新下载编译安装 查看版本 $ vmware -v VMware Workstation 17.5.1 build-23298084$ lsb_release…...
华为OD机试-食堂供餐-二分法
import java.util.Arrays; import java.util.Scanner;public class DemoTest3 {public static void main(String[] args) {Scanner in new Scanner(System.in);// 注意 hasNext 和 hasNextLine 的区别while (in.hasNextLine()) { // 注意 while 处理多个 caseint a in.nextIn…...
ardupilot 开发环境eclipse 中import 缺少C++
目录 文章目录 目录摘要1.修复过程摘要 本节主要解决ardupilot 开发环境eclipse 中import 缺少C++,无法导入ardupilot代码,会引起查看不方便的问题。如下图所示 1.修复过程 0.安装ubuntu 软件中自带的eclipse 1.打开eclipse—Help—install new software 2.在 Work with中…...
MySQL 8.0 OCP 英文题库解析(十三)
Oracle 为庆祝 MySQL 30 周年,截止到 2025.07.31 之前。所有人均可以免费考取原价245美元的MySQL OCP 认证。 从今天开始,将英文题库免费公布出来,并进行解析,帮助大家在一个月之内轻松通过OCP认证。 本期公布试题111~120 试题1…...
学习STC51单片机32(芯片为STC89C52RCRC)OLED显示屏2
每日一言 今天的每一份坚持,都是在为未来积攒底气。 案例:OLED显示一个A 这边观察到一个点,怎么雪花了就是都是乱七八糟的占满了屏幕。。 解释 : 如果代码里信号切换太快(比如 SDA 刚变,SCL 立刻变&#…...
Web 架构之 CDN 加速原理与落地实践
文章目录 一、思维导图二、正文内容(一)CDN 基础概念1. 定义2. 组成部分 (二)CDN 加速原理1. 请求路由2. 内容缓存3. 内容更新 (三)CDN 落地实践1. 选择 CDN 服务商2. 配置 CDN3. 集成到 Web 架构 …...
【JavaSE】多线程基础学习笔记
多线程基础 -线程相关概念 程序(Program) 是为完成特定任务、用某种语言编写的一组指令的集合简单的说:就是我们写的代码 进程 进程是指运行中的程序,比如我们使用QQ,就启动了一个进程,操作系统就会为该进程分配内存…...
