「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 容器,这几个容器的底层都是按照二叉搜索树来实现的。但是…...

AI-调查研究-01-正念冥想有用吗?对健康的影响及科学指南
点一下关注吧!!!非常感谢!!持续更新!!! 🚀 AI篇持续更新中!(长期更新) 目前2025年06月05日更新到: AI炼丹日志-28 - Aud…...

ESP32 I2S音频总线学习笔记(四): INMP441采集音频并实时播放
简介 前面两期文章我们介绍了I2S的读取和写入,一个是通过INMP441麦克风模块采集音频,一个是通过PCM5102A模块播放音频,那如果我们将两者结合起来,将麦克风采集到的音频通过PCM5102A播放,是不是就可以做一个扩音器了呢…...

网络编程(UDP编程)
思维导图 UDP基础编程(单播) 1.流程图 服务器:短信的接收方 创建套接字 (socket)-----------------------------------------》有手机指定网络信息-----------------------------------------------》有号码绑定套接字 (bind)--------------…...
安卓基础(aar)
重新设置java21的环境,临时设置 $env:JAVA_HOME "D:\Android Studio\jbr" 查看当前环境变量 JAVA_HOME 的值 echo $env:JAVA_HOME 构建ARR文件 ./gradlew :private-lib:assembleRelease 目录是这样的: MyApp/ ├── app/ …...
基于Java Swing的电子通讯录设计与实现:附系统托盘功能代码详解
JAVASQL电子通讯录带系统托盘 一、系统概述 本电子通讯录系统采用Java Swing开发桌面应用,结合SQLite数据库实现联系人管理功能,并集成系统托盘功能提升用户体验。系统支持联系人的增删改查、分组管理、搜索过滤等功能,同时可以最小化到系统…...
JavaScript 数据类型详解
JavaScript 数据类型详解 JavaScript 数据类型分为 原始类型(Primitive) 和 对象类型(Object) 两大类,共 8 种(ES11): 一、原始类型(7种) 1. undefined 定…...
快刀集(1): 一刀斩断视频片头广告
一刀流:用一个简单脚本,秒杀视频片头广告,还你清爽观影体验。 1. 引子 作为一个爱生活、爱学习、爱收藏高清资源的老码农,平时写代码之余看看电影、补补片,是再正常不过的事。 电影嘛,要沉浸,…...

uniapp 小程序 学习(一)
利用Hbuilder 创建项目 运行到内置浏览器看效果 下载微信小程序 安装到Hbuilder 下载地址 :开发者工具默认安装 设置服务端口号 在Hbuilder中设置微信小程序 配置 找到运行设置,将微信开发者工具放入到Hbuilder中, 打开后出现 如下 bug 解…...

实战三:开发网页端界面完成黑白视频转为彩色视频
一、需求描述 设计一个简单的视频上色应用,用户可以通过网页界面上传黑白视频,系统会自动将其转换为彩色视频。整个过程对用户来说非常简单直观,不需要了解技术细节。 效果图 二、实现思路 总体思路: 用户通过Gradio界面上…...

消息队列系统设计与实践全解析
文章目录 🚀 消息队列系统设计与实践全解析🔍 一、消息队列选型1.1 业务场景匹配矩阵1.2 吞吐量/延迟/可靠性权衡💡 权衡决策框架 1.3 运维复杂度评估🔧 运维成本降低策略 🏗️ 二、典型架构设计2.1 分布式事务最终一致…...