初步探索GraalVM--云原生时代JVM黑科技

news2024/11/16 5:50:41

1 云原生时代Java语言的困境

经过多年的演进,Java语言的功能和性能都在不断的发展和提高,诸如即时编译器、垃圾回收器等系统都能体现Java语言的优秀,但是想要享受这些功能带来的提升都需要一段时间的运行来达到最佳性能,总的来说Java是面向大规模、长时间使用的服务端应用而设计的。

云原生时代,Java语言一次编译到处运行的优势不复存在,理论上使用容器化技术,所有语言都能部署上云,而无法脱离JVM的Java应用往往要面对JDK内存占用比应用本身还大的窘境;Java动态加载、卸载的特性也使得构建的应用镜像中有一半以上的无用代码和依赖这些都使得Java应用占用内存相当多。而启动时间长,性能达到峰值的时间长使得在Serverless等场景下无法与Go、Node.js等快速语言竞争。

Java应用程序的运行生命周期示意图

2 GraalVM

面对云原生时代Java的不适,GraalVM或许是最好的解药。GraalVM是Oracle实验室推出的基于Java开发的开源高性能多语言运行时平台,它既可以在传统的 OpenJDK 上运行,也可以通过 AOT(Ahead-Of-Time)编译成可执行文件单独运行,甚至可以集成至数据库中运行。除此之外,它还移除了编程语言之间的边界,并且支持通过即时编译技术,将混杂了不同的编程语言的代码编译到同一段二进制码之中,从而实现不同语言之间的无缝切换。

本文主要简单从三个方面介绍GraalVM可以为我们带来的改变:

1)基于Java的Graal Compiler的出现对学习和研究虚拟机代码编译技术有着不可估量的价值,相比C++编写的复杂无比的服务端编译器,不管是对编译器的优化还是学习的成本都大大的降低。
2)静态编译框架Substrate VM框架,为Java在云原生时代提供了与其他语言竞争的可能,大大的减少了Java应用占用内存,并且可以加快启动速度几十倍。

3)以Truffle和Sulong为代表的中间语言解释器,开发者可以使用Truffle提供的API快速用Java实现一种语言的解释器,从而实现了在JVM平台上运行其他语言的效果,为Java世界带来了更多更有想象力的可能性。


GraalVM多语言支持

3 GraalVM整体结构

graal
├── CONTRIBUTING.md
├── LICENSE
├── README.md
├── SECURITY.md
├── THIRD_PARTY_LICENSE.txt
├── bench-common.libsonnet
├── ci-resources.libsonnet
├── ci.hocon
├── ci.jsonnet
├── ci_includes
├── common-utils.libsonnet
├── common.hocon
├── common.json
├── common.jsonnet
├── compiler
├── docs
├── espresso
├── graal-common.json
├── java-benchmarks
├── regex
├── repo-configuration.libsonnet
├── sdk
├── substratevm
├── sulong
├── tools
├── truffle
├── vm
└── wasm

3.1 Compiler

Compiler子项目全称GraalVM编译器,是用Java语言编写的Java编译器。高编译效率、高输出质量、同时支持提前编译(AOT)和即时编译(JIT)、同时支持应用于包括HotSpot在内的不同虚拟机的编译器。

与C2采用一样的中间表示形式(Sea of Nodes IR),后端优化上直接继承了大量来自于HotSpot的服务端编译器的高质量优化技术,是现在高校、研究院和企业编译研究实践的主要平台。

Graal Compiler是GraalVM与HotSpotVM(从JDK10起)共同拥有的服务端即时编译器,是C2编译器未来的替代者。为了让 Java 虚拟机与编译器解耦,ORACLE引入了Java-Level JVM Compiler Interface(JVMCI)Jep 243 :把编译器从虚拟机中抽离出来,并且可以通过接口与虚拟机交流(https://openjdk.java.net/jeps/243)

具体来说,即时编译器与 Java 虚拟机的交互可以分为如下三个方面。

  1. 响应编译请求;
  2. 获取编译所需的元数据(如类、方法、字段)和反映程序执行状态的 profile;
  3. 将生成的二进制码部署至代码缓存(code cache)里。


oracle提供的编译时间差异示例

3.2 Substrate VM

Substrate VM提供了将Java程序静态编译为本地代码的编译工具链,包括了编译框架、静态分析工具、C++支持框架及运行时支持等。在程序运行前便将字节码转换为机器码

优点:

  1. 从指定的编译入口开始静态可达性分析,有效的控制了编译范围,解决了代码膨胀的问题;
  2. 实现了多种运行时优化例如:传统的java类是在第一次被用到时初始化的,之后每次调用时还要再检查是否初始化过,GraalVM将其优化为在编译时初始化;
  3. 无需在运行过程中耗费CPU资源来进行即时编译,而程序也能在启动一开始就达到理想的性能;

缺点:

  1. 静态分析是资源密集型计算,需要消耗大量CPU、内存和时间;
  2. 静态分析对反射、JNI、动态代理的分析能力非常有限,目前GraalVM只能通过额外配置的方式加以解决;
  3. Java序列化也有多项违反封闭性假设的动态特性:反射,JNI,动态类载入,目前GraalVM也需要通过额外配置解决,且不能处理所有序列化,例如Lambda对象的序列化,而且性能是JDK的一半;

启动时长对比

占用内存对比

3.3 Truffle

我们知道一般编译器分为前端和后端,前端负责词法分析、语法分析、类型检查和中间代码生成,后端负责编译优化和目标代码生成。一种比较取巧的做法是将新语言编译成某种已知语言,如Scala、Kotlin可以编译成Java字节码,这样就可以直接享用JVM的JIT、GC等各项优化,这种做法都是针对的编译型语言。与之相对的,如JavaScript、Ruby、R、Python等解释型语言,它们依赖于解释执行器进行解析并执行,为了让这类解释型语言能够更高效的执行,开发人员通常需要开发虚拟机,并实现垃圾回收,即时编译等组件,让该语言在虚拟机中执行,如Google的V8引擎。如果能让这些语言也可以在JVM上运行并复用JVM的各种优化方案,将会减少许多重复造轮子的消耗。这也是Truffle项目的目标。

Truffle是一个用Java编写的解释器实现框架。它提供了解释器的开发框架接口,可以帮助开发人员用Java为自己感兴趣的语言快速开发处语言解释器,目前已经实现并维护了JavaScript、Ruby、R、Python等语言。

只需基于Truffle实现相关语言的词法分析器、语法分析器及针对语法分析所生成的抽象语法树(AST)的解释执行器,便可以运行在任何Java虚拟机上,享用JVM提供的各项运行时优化。

GraalVM多语言运行时性能加速比

3.3.1 Partial Evaluation

Truffle的实现原理基于Partial Evaluation这一概念:假设程序prog为将输入转为输出

其中Istatic为静态数据,在编译时已知常量,Idynamic为编译时未知数据,则可以将程序等价为:

新程序prog_为prog的特化,他应该会比原程序更高效的执行,这个从prog转换到prog_的过程便称为Partial Evaluation。我们可以将Truffle预压的解释执行器当成prog,将某段由Truffle语言写的程序当做Istatic,并通过Partial Evaluation将prog转换到prog*。

下面引用一个Oracle官方的例子来讲解,以下程序实现了读取参数以及参数相加的操作,需要实现读取三个参数相加:

这段程序解析生成的AST为

sample = new Add(new Add(new Arg(0), new Arg(1)), new Arg(2));

经过Partial Evaluator 的不断进行方法内联最终会变成下述代码:

3.3.2 节点重写

节点重写是Truffle的另一项关键优化。

在动态语言中许多变量的类型是在运行时才能确定的,以“加法”举例,符号+即可以表示整型相加也可以表示浮点型相加。Truffle的语言解释器会收集每个AST节点所代表的操作类型(profile),并且在编译时做出针对所收集到的profile进行优化,如:若收集到的profile显示这是一个整型加法操作,Truffle会在即时编译时将AST进行变形,将“+”视为整型加法。

当然,这种优化也会有错误的时候,比如上述加法操作既有可能是整数加法也可能是字符串加法,此时若AST树已变形,那么我们只好丢弃编译后的机器代码,回退到AST解释执行。这种基于类型 profile 的优化,背后的核心就是基于假设的投机性优化,以及在假设失败时的去优化。

在即时编译过后,如果运行过程中发现 AST 节点的实际类型和所假设的类型不同,Truffle 会主动调用 Graal 编译器提供的去优化 API,返回至解释执行 AST 节点的状态,并且重新收集 AST 节点的类型信息。之后,Truffle 会再次利用 Graal 编译器进行新一轮的即时编译。

据统计,在 JavaScript 方法和 Ruby 方法中,80% 会在 5 次方法调用后稳定下来,90% 会在 7 次调用后稳定下来,99%会在 19 次方法调用之后稳定下来。

3.4 Sulong

Sulong子项目是GraalVM为LLVM的中间语言bitcode提供的高新更运行时工具,是基于Truffle框架实现的bitcode解释器。Sulong为所有可以编译到LLVM bitcode的语言(如C,C++等)提供了在JVM中执行的解决方案。

4 参考

  • 林子熠 《GraalVM与静态编译》;
  • 周志明《深入理解Java虚拟机》;
  • Java Developer’s Introduction to GraalVM:-郑雨迪
  • Truffle/Graal:From Interpreters toOptimizing Compilers via Partial Evaluation:-Carnegie Mellon University

作者:王子豪

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/12272.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

linux笔记(5):按照东山派的官方教程编译buildroot(东山哪吒,D1-H)踩坑记录

文章目录1.编译流程1.1获取sdk源码1.2 补充:下载riscv64-glibc-gcc-thead_20200702.tar.xz1.3 补充:安装mtool工具1.4 安装必要依赖包1.5 编译sdcard 最小系统镜像1.6 烧录最小镜像系统到tf(SD)卡1.6.1 安装烧录工具1.6.2 格式化SD卡1.6.3 烧录镜像到sd卡…

杂篇(一)

开篇词 我本是红尘一俗客,没有那文人酸腐气。 曾几何时,梳理收藏夹,发现了很久前收藏的一位前端大佬的个人博客:怡红院落 ,因为领域不同,之前一直没有拜读过他的文章。 我尚且无法判断怡红公子购买的域名…

【Log日志】springboot项目中集成Log日志详解

springboot项目中集成Log日志详解一、Log日志介绍1.Log 日志组件主要作用及用途2.日志的级别Level级别控制3.日志的输出Import3.1 快速使用3.2 日志文件输出3.3 自定义配置4. Spring Boot 日志组件 Log Plugin二、Spring Boot Logback1.依赖配置 Pom.xml2.使用 YML 配置 logbac…

Linux操作系统~系统文件IO,什么是文件描述符fd?什么是vfs虚拟文件系统

目录 1.open() (1).第二个参数flags—通过比特位传多组标记 2.文件描述符fd(open函数的返回值) (1).fd的本质 (2).vfs-虚拟文件系统(一切皆文件) &…

MySQL Binlog 简介

MySQL Binlog Binlog 记录了所有的 DDL 和 DML(除了数据查询语句)语句,以事件形式记录,还包含语句所执行的消耗的时间,MySQL 的二进制日志是事务安全型的。 一般来说开启二进制日志大概会有 1%的性能损耗。 二进制日志包括两类文件&#xf…

seccon 2022 quals -simplemod

文章目录题外话调试思路如何找到对应的link_map分析do_lookup_x我的构造payloadall_exp总结题外话 这个题应该是seccon解题数量最少的了 这个题目其实和babyfile差不多,都是考虑0 lick,整体而言通过这两个题可以感受到出题者对于IO以及dl_resolv的理解深入 这个题目…

阻止移动端 touchmove 与 scroll 事件冲突

在移动端开发过程中,如果要实现一个元素或按钮的拖动定位,会出现很多坑。例如:元素上下移动过程中,会触发 body 的 scroll 事件,导致整体的位置偏移,这时就需要 阻止移动端 touchmove 与 scroll 事件冲突 。…

confluent-kafka-go依赖库编译体验优化

文章目录问题描述:解决方案1:编写Dockerfile文件2:运行Docker镜像3:进入镜像进行编译4:将编译成功的二进制文件复制到本机参考地址问题描述: ​ 在项目中使用了go的kafka库confluent-kafka-go,…

力扣(LeetCode)2. 两数相加(C++\C)

模拟 模拟加法运算,设置进位数 ttt , t(l1t(l1t(l1->vall2vall2vall2->valt)%10valt)\%10valt)%10 即为当前位上的数, t/10t/10t/10 即是进位数。 设置哑结点,便于操作头结点。 模拟上述操作,最后返回哑结点的…

Windows11更新最新系统版本后无法播放媒体声音

故障机器Dell为例 step1:检测系统提示音是否正常,正常可观察第二步; step2:打开计算机管理-设备管理器-观察声音设备是否正常,可右键编辑重启驱动 step3:打开无法播放媒体声音的设备查看设置,Firefox为例 …

腾讯魏巍:Eunomia云原生资源编排优化

2022年11月10日,在中国信通院、腾讯云、FinOps产业标准工作组联合发起的《原动力x云原生正发声 降本增效大讲堂》系列直播活动第10讲上,腾讯Light云计算平台负责人魏巍分享了Eunomia云原生资源编排优化实践。本文整理自魏巍的分享。 云上资源优化背景 相…

为你的服务器集成 LDAP 认证

本文内容 为什么需要 LDAP 认证如何集成 LDAP 认证Nginx 篇Apache 篇Backend 篇本文小结回顾我这些年的工作经历,面向企业(2B)和面向用户(2C)的项目都曾接触过。我个人觉得,面向企业的项目更注重业务,参与决策的人数多、周期长,目的是为企业提供生产经营价值,如缩减成本、…

kotlin coroutine源码解析之suspend挂起函数原理

目录suspend挂起函数join原理Await原理Suspend函数总结suspend挂起函数 在idea中写某些协程函数的时候,会有一个绿色箭头图标的出现,如下图: 而且这些方法不放在协程里面写的话,idea编辑器还会报错,如下图&#xff1…

基于python的人力资源管理系统

摘 要 随着当今社会的发展,时代的进步,各行各业也在发生着变化,比如人力资源管理这一方面,利用网络已经逐步进入人们的生活。传统的人力资源管理,都是员工去公司查看部门信息、招聘信息,这种传统方式局限性…

第一个 Go 程序,从 Hello World 开始

1、开发编辑器 Go 采用的是UTF-8编码的文本文件存放源代码,理论上使用任何一款文本编辑器都可以做 Go 语言开发,这里推荐使用 VS Code 和 Goland。 VS Code 是微软开源的编辑器,而 Goland 是 jetbrains 出品的付费IDE。GoLand 开发工具时收…

linux 安装微擎

前言 OS: CentOS Linux release 7.6.1810 (Core)nginx1.12.2微擎 v2.7.4 环境准备 PHP 7.0MYSQL 5.7 安装mysql 5.7 参考 【Docker】 安装 mysql 安装PHP 7.0 参考 Linux 利用yum源安装php7.0nginx PHP 支持 GD2 yum install php70w-gd*安装完成后重启php PHP 支持 D…

从感知机到神经网络

一、神经网络的一个重要性质 1.1 重要性质 自动从数据中学习到合适的权重参数 1.2 称呼 共n层神经元,称之为n-1层网络 输入层中间层(隐藏层)输出层 1.3计算神经网络 节点值*权重值偏置值输出值 根据输出值的大小计算出节点值 输出值…

ICV:全球首份量子重力测量仪器市场分析报告。传统测量行业地位正被量子传感器商业化严重威胁,中国有望成为量子重力测量仪器市场最大赢家!

本报告的主要内容是对量子重力测量仪器进行市场分析,并对量子重力测量仪器科研方向、主要企业、关键应用、产业现状(科研需求、军用场景)、未来趋势等方面进行分析及预测未来的市场发展。 量子重力传感器原理为在真空环境中利用激光和磁场捕获…

11、Service访问Pod、Service IP原理、DNS访问Service、外部访问service

Pod可能因为各种原因发生故障而死掉,Deployment等Controller会通过动态创建和销毁Pod来保障应用整体的健壮性。Pod是脆弱的,但应用是健壮的。每个Pod都有自己的IP地址,当controller用新的Pod替代发生故障的Pod时,新Pod会分配到新的…

【Linux】Ubuntu、Debian下对deb包进行修改后重新打包——以MySQL安装包为例

需求 关于MySQL的lower_case_table_names参数,在Windows系统下和在Linux系统下,默认值是不同的。 Unix,Linux下默认为0,大小写敏感。创建的库表名将原样保存在磁盘上。如create database TeSt;将会创建一个TeSt的目录&#xff0…