An Introduction to JWarmup

简介: 一、JWarmup背景 二、JWarmup功能 三、案例演示

一、JWarmup背景 

(一)应用程序预热 

Java的方法要被执行,首先这个方法所在的类需要被JVM加载,这个过程包括各类文件的验证、解析、链接以及类的初始化。当这个类被加载进来了以后,JVM就可以去执行这个方法。 

JVM在刚开始的时候会使用模板解释器去解释执行方法,模板解释器除了一个个去执行方法中的Bytecodes之外,还会额外收集关于方法执行动态运行的信息,例如方法执行的调用次数,调用时一些类型的信息等。这些信息都会提供给JVM的即时编译器,由它利用这些信息将刚才解释执行发现的热点方法编译成为Native Code。这样JVM就不用模板解释器去执行这些方法,而是去执行性能更高的Native Code,从而使应用程序的性能得到大幅提升。 

当大多数热点方法都被编译成为Native Code以后,应用程序的预热就完成了 

 

(二)遇到的问题 

Java有非常丰富的应用场景,一个典型的场景就是我们会用Java写一些 Web服务在Web服务的部署过程中,会发现预热给我们带来非常大的困扰。当我们把一个Web服务部署到线上后,应用启动完成,此时就会有大量的用户请求进入。 

这个时候由于有大量的热点方法需要被编译,JVM的编译线程会非常忙碌,因为它需要占用大量的CPU将这些方法编译成为Native Code。同时又因为用户的线程需要执行解决用户的请求,因此它也会占用大量的CPU,并且会抢占编译线程所使用的CPU,这样就会导致编译线程无法尽快把这些热点方法编译到Native Code,使得应用程序长时间运行在解释执行的状态,降低服务的质量同时服务的RT会增加,服务所使用的CPU也会非常的高,这就是在真实场景中所遇到应用程序预热的问题接下来我们来看一下阿里巴巴Dragonwell 8中的JWarmup特性是如何解决这个问题。 

 

 

二、JWarmup功能 

image.jpeg 

上方为JWarmup流程图,它将应用程序的发布分成了两个阶段,分别是Recording和Replaying。在Recording阶段,JVM会接受线上的请求,同时记录JVM即时编译器它所编译方法的信息,并且将这些信息都输出到一个文件之中。 

等到第二次再去启动的时候,JVM就可以去读取刚刚所记录的这些方法编译的信息,同时会主动的触发即时编译器编译刚刚记录的热点方法,使得在用户请求到来之前,就把热点方法编译成为性能较高的Native Code,避免了用户请求大量进入的时候做编译,这样就能够进一步提高应用程序的性能,节约CPU使用率。 

 

 

三、案例演示 

(一)Demo代码 

image.png 

下面根据一个简单的例子展示如何使用JWarmup功能 

上方为一个简单的 Java程序,在这个程序之中有一个循环用来模拟线上应用的一个热点,循环会反复调用一个方法。 

 

(二)Recording 

如何去使用JWarmup的记录功能Recording 

-XX:+CompilationWarmUpRecording 

-XX: CompilationWarmUpRecording=30 

-XX: CompilationWarmUpLogfile=./jwarmup.log 

-XX:-ClassUnloading 

第一个参数表示去打开JWarmup的记录功能 

第二个参数表示需要记录的时间,在当前Demo之中选择记录30秒 

第三个参数表示记录编译信息生成文件的路径在这个Demo中,我们将这个文件生成在当前目录下的jwarmup.log这个文件 

第四个参数由于JWarmup的Recording功能不支持ClassUnloading,所以需要将这一功能关闭。 

设定的记录时间到了以后,JWarmup会将记录好的编译信息输出到指定的文件之中,同时会在应用程序的输出中看到以下这样一条日志,表明记录是成功的。 

image.png 

 

(三)Replaying 

如何使用JWarmup的Replaying功能 

  • 添加JVM参数: 

-XX:+CompilationWarmUp 

-XX:+CompilationWarmUpLogfile=./jwarmup.log 

-XX:+PrintCompilationWarmUpDetail 

第一个参数表示使用JWarmup的编译功能 

第二个参数需要指定刚刚记录的包含编译信息的文件,在当前Demo之中,就是刚刚所记录的当前目录下的jwarmup.log文件 

第三个参数表示我希望JWarmup打印出一些详细的日志,帮助我记录JWarmup工具的一些行为 

当把这些参数配置好以后,将服务启动,等待一些关键的类的加载完成可以使用jcmd <pid> JWarmup -notify主动触发Warmup的编译。 

Warmup编译完成后,可以在程序的标准输出中看到下面三条log,就表示这一次Warmup编译是成功的 

image.png 

以上就是关于JWarmup的基本介绍,包含JWarmup所需要解决的问题,解决方法,以及用案例讲述如何使用JWarmup功能同时我们对JWarmup这个功能还做了非常多的改进,形成了我们另外一份工作:JWarmup2 

image.png 

上方为JWarmup2整体流程图,可以看到在这份工作之中,我们记录了更加丰富的信息,去更好解决应用程序预热的问题。 

首先我们会使用JFR(Java Flight Recorder)统一所记录的编译的信息,这些信息也可以形成一个JFR文件,使用JDK官方所提供的Java Mission Control浏览所记录的所有热点方法的信息 

此外我们除了记录一些方法的编译,还记录了每一个方法它所依赖的类的信息。这样子在我们第二步预热的时候,就可以根据这些依赖的信息,当我们看到一个方法,它所有的依赖的类都被加载了以后,就会自动触发这个方法的Warmup编译,避免了人工手动触发Warmup编译 

此外我们还额外记录了这些方法所有的Profiling信息,这些信息能够帮助我们在第二步去更好地生成Warmup的代码,从而进一步提高应用程序的性能 

JWarmup2未来将在阿里巴巴Dragonwell 11中开源,欢迎大家使用。 

相关文章
|
安全 Java 编译器
阿里巴巴Dragonwell
阿里巴巴Dragonwell
Alibaba Dragonwell 试用评测
Alibaba Dragonwell 8 是一款免费的 OpenJDK 发行版。它提供长期支持,包括性能增强和安全修复。Alibaba Dragonwell 8 目前支持 X86-64/Linux 平台,在数据中心大规模 Java 应用部署情况下, 可以大幅度提高稳定性、效率以及性能。
6429 0
|
自然语言处理 Java Go
Fury:一个基于JIT动态编译的高性能多语言原生序列化框架
Fury是一个基于JIT动态编译的多语言原生序列化框架,支持Java/Python/Golang/C++等语言,提供全自动的对象多语言/跨语言序列化能力,以及相比于别的框架最高20~200倍的性能。
Fury:一个基于JIT动态编译的高性能多语言原生序列化框架
|
机器学习/深度学习 并行计算 Java
【java】 vector api 快速入门
【java】 vector api 快速入门
1382 0
|
缓存 自然语言处理 JavaScript
万字长文深度解析JDK序列化原理及Fury高度兼容的极致性能实现
Fury是一个基于JIT动态编译的高性能多语言原生序列化框架,支持Java/Python/Golang/C++/JavaScript等语言,提供全自动的对象多语言/跨语言序列化能力,以及相比于别的框架最高20~200倍的性能。
169095 12
|
监控 安全 Java
JVM工作原理与实战(三十八):JIT即时编译器原理
JVM作为Java程序的运行环境,其负责解释和执行字节码,管理内存,确保安全,支持多线程和提供性能监控工具,以及确保程序的跨平台运行。本文主要介绍了JIT即时编译器、HotSpot中的JIT编译器、JIT优化技术、JIT优化建议等内容。
396 0
|
缓存 Java 编译器
Java 中的 JIT 和 AOT
我们都知道,Java 是一种半编译型,半解释型的语言,其编译部分和 C++ 语言比较类似,解释部分和 Python 语言比较类似,而 Java 则是综合了两种方式的语言。
656 1
|
Java Linux iOS开发
Dragonwell JDK系统要求
Dragonwell JDK系统要求
|
存储 分布式计算 JavaScript
Fury系列(四):一个比Kryo/Hessian快30~40倍的类型前后兼容序列化器
问题背景类型前后兼容是复杂业务场景序列化的常见需求。在快速迭代的业务场景当中,读写端经常发生对象字段发生变更:在线应用场景:线上SOFA/HSF应用提供服务给多个调用方,服务的滚动升级以及各个调用方独立更新都可能导致对象类型不一致的情况;在线服务场景:在线服务框架常驻不更改对象类型,但调用方业务逻辑变动独立更新导致对象字段跟服务端不一致;对象持久化场景:对象数据序列化后持久化写入存储(如Spark
2028 2
Fury系列(四):一个比Kryo/Hessian快30~40倍的类型前后兼容序列化器