---
title: 通过分层编译优化解决JDK性能问题案例分享-官方技术文章-鲲鹏社区
description: 本文章记录一次OracleJDK替换为毕昇JDK后性能异常的定位过程和简单介绍java的即时编译（JIT）。
keywords: JDK,通过分层编译,优化解决,性能问题案例,分享,官方技术文章,鲲鹏社区,调优分析
url: https://www.hikunpeng.com/developer/techArticles/20250522-1?envFlag=1
section: (其他)
---

# 通过分层编译优化解决JDK性能问题案例分享-官方技术文章-鲲鹏社区

URL: https://www.hikunpeng.com/developer/techArticles/20250522-1?envFlag=1
描述: 本文章记录一次OracleJDK替换为毕昇JDK后性能异常的定位过程和简单介绍java的即时编译（JIT）。
关键词: JDK,通过分层编译,优化解决,性能问题案例,分享,官方技术文章,鲲鹏社区,调优分析

官方技术文章 [了解详情](https://www.hikunpeng.com/zh/developer/techArticles)

通过分层编译优化解决JDK性能问题案例分享

通过分层编译优化解决JDK性能问题案例分享

javajdk

发表于 2025/05/22

0

作者|丁浩源

问题背景

在次JDK迁移测试中，从OracleJDK迁移到毕昇JDK，在有些测试用例上，性能出现劣化，记录一次分析定位问题的过程

软件信息

| 软件名称 | 版本 | 备注 |
| --- | --- | ---|
| 毕昇JDK | 1.8.0_442 | 替换oraclejdk
  1.8_202, 1.8_291 |

测试数据

有四个用例：  通过自研的java程序测试这四种场景的性能数据，单位s，
表示跑完这4个用例所需的时间。

oraclejdk 1.8_202:

| 线程数 | test1 | test2 | test3 | test4 |
| --- | --- | --- | --- | ---|
| 80 | 52 | 200 | 70 | 75 |

oracleJDK 1.8.0_291

| 线程数 | test1 | test2 | test3 | test4 |
| --- | --- | --- | --- | ---|
| 80 | 50 | 150 | 61 | 80 |

毕昇JDK：

| 线程数 | test1 | test2 | test3 | test4 |
| --- | --- | --- | --- | ---|
| 80 | 50 | 65 | 45 | 145 |

可以看到前三项测试毕昇JDK性能持平或者领先oracleJDK，第四项测试性能存在落后。

# 调优分析

## 1） 整体情况

当前主要test4存在落后测试test4用例的,80并发测试的时候后发现CPU使用较高，达90%左右，整体属于高负载情况。

## 2） CPU

压测时CPU较高，达90%，为计算密集型测试用例。

## 3）内存

通过GC日志，可以看到JVM的一些配置信息：

CommandLine flags: -XX:InitialHeapSize=2147483648
-XX:MaxHeapSize=32210157568 -XX:+PrintGC -XX:+PrintGCDetails
-XX:+PrintGCTimeStamps -XX:+UseCompressedClassPointers -XX:+UseCompressedOops
-XX:+UseParallelGC

堆内存最大30G，内存充足。

## 4）GC情况

以下是GC日志：

可以看到GC日志正常，GC时间10ms以下，非常迅速。

## 5）热点函数

通过perf top 查看运行的热点，发现

主要是JIT的热点，表明程序正在大规模进行编译优化。 这是在预期之内的，因为从用例上看

是执行大规模的循环操作，这些高频热点函数，JVM会进行编译优化，编译成机器码高效执行，避免解释执行。

## 6）火焰图分析

通过devkit分别抓取两种JDK运行时候的java进程的火焰图，我们发现毕昇JDK的火焰图执行堆栈和OracleJDK一致，因此执行路径上没有差别，是执行效率的问题，同一个方法的执行比较慢，怀疑是JIT编译优化的差距，oracle
JDK使用了更高级别的优化方法，比如直接使用了C2编译。

调优方法

1） 避免编译退优化

当一个方法执行多次后，JVM会对这个方法进行及时编译生成机器码，机器码的执行效率远超解释执行。

过程简化为： 解释执行
-> C1编译 -> C2编译

执行的效率为 C2 >
C1 > 解释执行。

当前函数执行到一定的次数会触发C1编译，当C1编译的机器码执行到一定的次数或者循环回边到达一定次数会触发C2编译。

当JVM检查到上次函数的编译不是最优的比如（类型预测失败，锁状态变化等）会触发重新编译，但是默认来讲一个函数有最大的编译次数限制，最大阈值为参数-XX:PerMethodRecompilationCutoff控制，一旦到达这个值，该函数将不在继续编译优化，将会一直使用上一个编译版本进行运行。

措施： JVM设置-XX:PerMethodRecompilationCutoff=-1，表示不限制编译优化次数，可以保证函数一直进行优化，防止出现退优化场景。

调优后数据

| 线程数 | test1 | test2 | test3 | test4 |
| --- | --- | --- | --- | ---|
| 80 | 55 | 120 | 57 | 90 |

## 2） 分层编译

及时编译在绝大多数JDK中默认是按分层编译进行的，即：先进行C1编译，运行到一定程度之后再进行C2编译。 C1的CPU耗费较少， 但优化程度较低；C2的CPU耗费较多，但优化程度更高，执行效率更高。通过获取java -XX:+PrintFlagsFinal -version | grep TieredCompilation 查看分层编译是否在jdk层面打开，结果发现：bisheng JDK：bool TieredCompilation = true {pd product}oracle JDK：bool TieredCompilation = false {pd product}毕昇JDK是按照业界惯例打开的，oracle的该发行版是的。如果分层编译，那么编译器将跳过C1直接使用C2编译。所编译出来的机器码是优化程度更高的，但代价是资源消耗更高一些。程序可以通过设置JVM参数：-XX:-TieredCompilation 分层编译。

调优后数据

| 线程数 | test1 | test2 | test3 | test4 |
| --- | --- | --- | --- | ---|
| 80 | 45 | 91 | 42 | 85 |

上面两种措施都可以提升该测试场景的性能，措施实施之后，毕昇JDK的整体性能领先OracleJDK。

# 调优总结

因为该OracleJDK的分层编译是的，所以性能表现较好，如果将毕昇JDK的分层编译，在该测试用例上性能整体领先oracleJDK。

对于该用例：
可以将分层编译可以大幅提升性能。 但对于正式业务，需要具体测试判断，一般还是建议打开分层编译，可以根据具体业务场景来通过设置-XX:PerMethodRecompilationCutoff=-1，不限制编译次数来提升性能。

本页内容
