轩辕李的博客 轩辕李的博客
首页
  • Java
  • Spring
  • 其他语言
  • 工具
  • HTML&CSS
  • JavaScript
  • 分布式
  • 代码质量管理
  • 基础
  • 操作系统
  • 计算机网络
  • 编程范式
  • 安全
  • 中间件
  • 心得
关于
  • 分类
  • 标签
  • 归档
GitHub (opens new window)

轩辕李

勇猛精进,星辰大海
首页
  • Java
  • Spring
  • 其他语言
  • 工具
  • HTML&CSS
  • JavaScript
  • 分布式
  • 代码质量管理
  • 基础
  • 操作系统
  • 计算机网络
  • 编程范式
  • 安全
  • 中间件
  • 心得
关于
  • 分类
  • 标签
  • 归档
GitHub (opens new window)
  • Java

    • 核心

      • Java8--Lambda 表达式、Stream 和时间 API
      • Java集合
      • Java IO
      • Java 文件操作
      • Java 网络编程
      • Java运行期动态能力
      • Java可插入注解处理器
      • Java基准测试(JMH)
      • Java性能分析(Profiler)
        • 引言
          • 1 Java性能分析的重要性
          • 2 Profiler的作用和用途
        • 常见的Java Profiler工具
          • 1 Java VisualVM
          • 2 YourKit Java Profiler
          • 3 JProfiler
          • 4 IntelliJ IDEA Profiler
          • 5 Java Flight Recorder (JFR)
        • Profiler的主要功能
          • 1 CPU分析
          • 2 内存分析
          • 3 垃圾收集分析
          • 4 线程分析
          • 5 I/O分析
          • 6 对象分配分析
          • 7 报告和可视化
        • 使用Profiler进行性能分析的步骤
          • 1 选择合适的Profiler工具
          • 2 配置Profiler
          • 3 运行性能分析
          • 4 分析Profiler结果
          • 5 优化代码和配置
          • 6 重新运行性能分析并评估改进效果
        • 实战
          • 1 IntelliJ IDEA Profiler实战
          • CPU分析
          • 运行时的数据分析
          • 2 堆转储文件
          • 3 JFR文件分析
        • 结论
          • 1 Profiler在Java性能分析中的关键作用
          • 2 理解Profiler工具的原理和功能
          • 3 选择合适的Profiler工具以优化Java应用性能
      • Java调试(JDI与JDWP)
      • Java管理与监控(JMX)
      • Java加密体系(JCA)
      • Java服务发现(SPI)
      • Java随机数生成研究
      • Java数据库连接(JDBC)
      • Java历代版本新特性
      • 写好Java Doc
      • 聊聊classpath及其资源获取
    • 并发

    • 经验

    • JVM

    • 企业应用

  • Spring

  • 其他语言

  • 工具

  • 后端
  • Java
  • 核心
轩辕李
2023-05-01
目录

Java性能分析(Profiler)

# 引言

# 1 Java性能分析的重要性

在现代软件开发中,应用性能对于提供良好的用户体验和确保资源使用效率至关重要。

对于Java应用来说,性能分析是一个关键的环节,它可以帮助开发者发现潜在的性能瓶颈、内存泄漏以及线程竞争等问题。

通过定期进行性能分析并针对性地优化代码,可以显著提高Java应用的性能和稳定性。

# 2 Profiler的作用和用途

Profiler是一种性能分析工具,用于监控和分析Java应用在运行时的性能表现。

它可以收集应用的CPU使用情况、内存分配、垃圾回收活动、线程状态等多方面的信息,以帮助开发者诊断并解决性能问题。

此外,Profiler还可以提供深入的分析功能,如调用栈跟踪、热点方法识别等,使得开发者能够更有效地定位问题根源。

# 常见的Java Profiler工具

在Java生态系统中,有许多优秀的Profiler工具可供选择。以下是一些常见的Java Profiler工具:

# 1 Java VisualVM

Java VisualVM是一款免费的、由Oracle提供的性能分析和监控工具。它集成了多个Java虚拟机(JVM)相关的工具,如jstat、jstack和jmap等,并提供了一个统一的用户界面。Java VisualVM可以实现CPU分析、内存分析、垃圾回收分析等基本功能,并支持插件扩展以增强其功能。

# 2 YourKit Java Profiler

YourKit Java Profiler是一款商业性能分析工具,提供了丰富的功能和优秀的性能。除了基本的CPU分析、内存分析和垃圾回收分析等功能外,YourKit还提供了许多高级功能,如数据库查询分析、文件I/O分析等。此外,YourKit还具有强大的集成能力,可以无缝地与各种IDE和持续集成工具进行集成。

# 3 JProfiler

JProfiler是另一款商业性能分析工具,同样拥有丰富的功能和良好的性能。JProfiler的特点包括详细的CPU分析、内存分析、线程分析等功能,以及支持分布式应用和集群环境的性能分析。JProfiler还具有高度可定制的界面和丰富的报告功能,方便开发者对性能数据进行深入分析。

# 4 IntelliJ IDEA Profiler

IntelliJ IDEA是一款非常受欢迎的Java集成开发环境(IDE),它内置了一个简单的Profiler工具,可以在开发过程中对Java应用进行性能分析。虽然功能相对有限,但IntelliJ IDEA Profiler对于快速识别性能问题和进行基本的性能调优非常有帮助。由于其与IDE的紧密集成,开发者可以方便地在代码编辑、调试和性能分析之间进行切换。

# 5 Java Flight Recorder (JFR)

Java Flight Recorder(JFR)是一款由Oracle官方提供的高级性能分析工具,集成在Java虚拟机(JVM)中,从Java 11开始成为OpenJDK的一部分。JFR旨在通过低开销地收集诸如CPU使用情况、内存分配、垃圾回收活动、线程状态等各种运行时指标,帮助开发者诊断Java应用的性能问题。

JFR具有以下优点:

  1. 低开销:由于JFR直接集成在JVM内部,因此在收集性能数据时具有较低的性能开销。
  2. 灵活性:JFR支持开发者自定义收集的事件和指标,可以针对特定的性能问题进行深入分析。
  3. 易于使用:JFR的使用方式相对简单,可以通过命令行或编程接口来启动和配置性能记录。

需要注意的是,虽然JFR具有强大的性能分析功能,但其用户界面相对简单,可能不如其他专业Profiler工具直观。为了更好地分析和可视化JFR收集的数据,开发者可以使用诸如JDK Mission Control(JMC)等辅助工具。

# Profiler的主要功能

接下来,我们将介绍Java Profiler工具的一些主要功能,这些功能在不同的Profiler工具中可能有所差异,但总体上都具有类似的目的和作用。

# 1 CPU分析

CPU分析用于收集Java应用在运行过程中对CPU资源的使用情况。通过CPU分析,开发者可以了解应用中哪些方法和操作占用了较多的CPU时间,从而找出性能瓶颈和优化方向。Profiler工具通常会提供热点方法列表、调用栈跟踪和调用图等功能,帮助开发者深入了解代码的执行情况。

# 2 内存分析

内存分析用于监控和分析Java应用的内存使用和分配情况。通过内存分析,开发者可以发现内存泄漏、过度分配和对象存活时间过长等问题。Profiler工具通常会提供内存使用趋势图、对象分配统计和对象引用分析等功能,帮助开发者优化内存使用和垃圾回收策略。

# 3 垃圾收集分析

垃圾收集分析用于监控和分析Java虚拟机的垃圾回收活动。通过垃圾收集分析,开发者可以了解垃圾回收器的运行情况,包括回收次数、回收耗时和回收效果等。Profiler工具通常会提供垃圾收集日志解析、垃圾收集指标图表和垃圾收集器配置建议等功能,帮助开发者优化垃圾回收性能。

# 4 线程分析

线程分析用于监控和分析Java应用中的线程状态和活动情况。通过线程分析,开发者可以发现线程竞争、死锁和资源争用等问题。Profiler工具通常会提供线程列表、线程状态图表和线程锁分析等功能,帮助开发者优化多线程性能和并发策略。

# 5 I/O分析

I/O分析用于监测和分析Java应用的输入/输出(I/O)操作。通过I/O分析,开发者可以了解应用中文件、网络和数据库等资源的使用情况,从而找出潜在的性能瓶颈。Profiler工具通常会提供I/O操作统计、资源访问跟踪和性能建议等功能,帮助开发者优化资源访问和管理策略。

# 6 对象分配分析

对象分配分析用于监控和分析Java应用在运行过程中对象的创建和分配情况。通过对象分配分析,开发者可以了解哪些类的实例被频繁创建,从而找出可能存在的性能问题和优化方向。Profiler工具通常会提供对象分配统计、实例创建跟踪和内存使用分析等功能,帮助开发者了解对象分配的细节,并针对性地进行内存管理优化。

对象分配分析可以帮助识别以下几类问题:

  1. 过度对象创建:频繁创建大量对象可能导致性能瓶颈,尤其是在创建过程中涉及到较多资源分配和初始化操作时。通过对象分配分析,可以找到过度创建的对象并考虑使用对象池等技术进行优化。

  2. 内存泄漏:对象分配分析可以帮助发现意外保留的对象引用,从而导致的内存泄漏。分析工具通常会提供对象引用分析功能,使开发者能够追踪到导致内存泄漏的代码位置。

  3. 对象存活时间过长:对象存活时间过长可能导致垃圾回收器无法及时回收无用对象,进而影响内存使用效率。通过对象分配分析,可以了解对象的生命周期,并针对性地调整代码逻辑以减少对象存活时间。

  4. 不合理的内存分配策略:对象分配分析有助于发现不合理的内存分配策略,例如过大或过小的初始内存分配,或者不合适的内存增长策略。根据分析结果,开发者可以调整内存分配参数以提高内存使用效率。

# 7 报告和可视化

报告和可视化功能用于将Profiler收集到的性能数据以图表、表格和文字等形式呈现给开发者。Profiler工具通常会提供丰富的报告模板、可定制的视图和导出功能等,使得开发者能够更直观地分析性能数据并制定优化策略。

# 使用Profiler进行性能分析的步骤

下面我们将介绍使用Profiler进行性能分析的主要步骤。

# 1 选择合适的Profiler工具

首先,需要根据项目需求和开发环境选择合适的Profiler工具。在选择时,可以考虑以下因素:

  • 功能需求:根据需要分析的性能问题,确保所选工具能够提供相应的分析功能,例如CPU分析、内存分析、线程分析等。
  • 平台兼容性:确保所选工具支持开发和运行环境,例如操作系统、JVM版本等。
  • 集成性:优先选择与所使用的开发工具(如IDE)紧密集成的Profiler工具,以便在编码、调试和性能分析之间无缝切换。
  • 易用性:选择易于上手和使用的工具,以减少学习和配置的成本。

# 2 配置Profiler

在选择好Profiler工具后,需要对其进行配置,以确保正确地监控和收集性能数据。配置内容可能包括:

  • 选择要监控的性能指标和事件。
  • 设置采样频率和数据收集范围。
  • 配置报警阈值和通知方式(如果支持)。
  • 配置性能数据的存储和导出选项。

# 3 运行性能分析

配置好Profiler后,可以开始运行性能分析。通常,性能分析可以在以下场景中进行:

  • 开发过程中,对疑似存在性能问题的代码进行分析。
  • 集成测试阶段,对整个应用进行全面的性能评估。
  • 生产环境中,对实际运行状态下的应用进行性能监控和分析。

# 4 分析Profiler结果

运行性能分析后,需要对收集到的性能数据进行分析。分析过程中,可以关注以下几点:

  • 找出热点方法和操作,找出性能瓶颈。
  • 分析内存使用和垃圾回收情况,发现内存泄漏和过度分配等问题。
  • 分析线程状态和活动,找出线程竞争和死锁等问题。
  • 分析I/O操作,找出资源访问和管理的性能瓶颈。

# 5 优化代码和配置

根据性能分析结果,针对性地对代码和配置进行优化。优化措施可能包括:

  • 优化算法和数据结构,降低时间复杂度和空间复杂度。
  • 优化内存分配策略,减少内存泄漏和过度分配。
  • 优化多线程和并发策略,减少线程竞争和死锁等问题。
  • 优化I/O操作,改善资源访问和管理性能。
  • 调整JVM参数和垃圾回收器设置,提高内存利用率和回收效率。
  • 调整操作系统参数和硬件配置,以提高整体性能。

在进行优化时,应注意遵循代码可读性和可维护性的原则,避免过度优化导致的代码质量下降。

# 6 重新运行性能分析并评估改进效果

在完成优化后,需要重新运行性能分析,以评估改进措施的实际效果。通过对比优化前后的性能数据,可以了解优化措施是否达到预期效果,以及是否存在新的性能瓶颈。

如果优化效果不理想或存在新的问题,可以继续迭代优化过程,直到达到满意的性能水平。在实际项目中,性能优化往往是一个持续的过程,需要开发者不断关注应用的性能表现,并根据实际需求和环境变化进行调整和优化。

# 实战

# 1 IntelliJ IDEA Profiler实战

从IntelliJ IDEA 2020.3版本开始,IntelliJ Profiler默认使用Java Flight Recorder (JFR)作为其性能分析引擎。这意味着在IntelliJ IDEA中进行性能分析时,实际上是在使用JFR收集性能数据。这使得IntelliJ Profiler可以提供更详细、更精确的性能分析结果。

# CPU分析

定义一个斐波那契数列:

public class Fibonacci {
    public static long fib(int n) {
        if (n <= 1) {
            return n;
        }
        return fib(n - 1) + fib(n - 2);
    }

    public static void main(String[] args) {
        for (int i = 1; i <= 40; i++) {
            System.out.println("Fibonacci of " + i + " is: " + fib(i));
        }
    }
}

在main方法的右侧点击运行,选择IntelliJ Profiler:
image

运行结束后打开Profiler窗口:
image

可以看到一个火焰图,火焰图上的数据基本上是所有采样堆的汇总。分析器收集的具有相同堆栈的样本越多,此堆栈在火焰图上的增长就越宽。

因此,帧的宽度大致等于在此状态下花费的时间份额。至于颜色:栈中黄色的部分是Java代码,蓝色的是本地方法调用。

CPU分析需要程序运行结束后,得到一份jfr数据,才能进行分析。

# 运行时的数据分析

有以下代码示例:

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.*;
import java.util.concurrent.TimeUnit;

public class CountEvents {

    public static int update(Deque<Long> events, long nanos, long interval) {
        events.add(nanos);
        events.removeIf(aTime -> aTime < nanos - interval);
        return events.size();
    }

    public static void main(String[] args) throws IOException {
        long start = System.nanoTime();
        int total = 100_000;
        long interval = TimeUnit.MILLISECONDS.toNanos(100);
        int[] count = new int[total];

        Deque<Long> collection = new ArrayDeque<>();
        for (int counter = 0; counter < count.length; counter++) {
            count[counter] = update(collection, System.nanoTime(), interval);
            Path p = Paths.get("./a/b");
            Files.createDirectories(p);
        }
        long spent = System.nanoTime() - start;

        //noinspection OptionalGetWithoutIsPresent
        System.out.println("Average count: " + (int) (Arrays.stream(count).average().getAsDouble()) + " op");
        System.out.println("Spent time: " + TimeUnit.NANOSECONDS.toMillis(spent) + " ms");
    }
}

这个示例会运行一段时间,在运行期间我们在Profiler窗口可以看到它:
image

右键点击运行中的程序:
image

看到内存快照:
image

和CPU内存实时图表:
image

# 2 堆转储文件

使用jdump获得堆转储文件:jmap -dump:format=b,file=<filename> <pid>,然后在IDEA中打开文件,可以看到内存快照分析。

# 3 JFR文件分析

对于JFR的使用,第一种方式是:-XX:+UnlockCommercialFeatures -XX:+FlightRecorder -XX:StartFlightRecording=duration=60s,filename=myrecording.jfr

其中,-XX:+UnlockCommercialFeatures参数开启了商业功能,而-XX:+FlightRecorder参数开启了 JFR。

-XX:StartFlightRecording 参数来指定记录器的选项,包括记录器的持续时间和文件名。

具体来说,-XX:StartFlightRecording 参数的语法为:

-XX:StartFlightRecording=<option1>=<value1>,<option2>=<value2>,...

其中,<option> 表示记录器的选项,<value> 表示选项的值,多个选项之间用逗号分隔。常用的选项包括:

  • duration:指定记录器的持续时间,可以是一个整数加上时间单位(例如 60s 表示 60 秒,5m 表示 5 分钟)。
  • filename:指定记录文件的名称和路径。
  • maxsize:指定记录文件的最大大小,可以是一个整数加上大小单位(例如 256m 表示 256MB)。
  • settings:指定 JFR 配置文件的路径。

因此,-XX:StartFlightRecording=duration=60s,filename=myrecording.jfr 的意思是,启用 JFR 记录器,持续时间为 60 秒,记录文件的名称为 myrecording.jfr。


第二种方式是使用jcmd:

  1. 确保 JDK 11 已经正确安装。可以通过运行 java -version 命令来检查 JDK 版本号。

  2. 在应用程序启动时加上以下 JVM 参数,以开启 JFR:

-XX:+UnlockCommercialFeatures -XX:+FlightRecorder

其中,-XX:+UnlockCommercialFeatures 参数开启了商业功能,而 -XX:+FlightRecorder 参数开启了 JFR。

  1. 使用以下命令启动 JFR 进行记录:
jcmd <pid> JFR.start name=myrecording

其中,<pid> 是应用程序进程的 ID,name=myrecording 是指定的记录器名称,可以是任何合法的字符串。JFR 记录器可以记录多个事件,包括 CPU、内存、线程、I/O 等方面的事件。

  1. 执行一些操作或负载,以收集足够的数据。

  2. 停止记录器并保存记录文件:

jcmd <pid> JFR.stop name=myrecording filename=myrecording.jfr

其中,filename=myrecording.jfr 指定了记录文件的保存路径和文件名。

获得的jfr文件,在IDEA中打开,可以看到火焰图、调用树、事件等信息。

提示:jfr文件同样可以在JMC(Java Mission Control)中打开查看,JMC是一个免费的开源工具,官网是:Java Mission Control (opens new window)

# 结论

# 1 Profiler在Java性能分析中的关键作用

Profiler在Java性能分析中扮演着关键的角色。

它可以帮助开发者发现和诊断应用程序中的性能瓶颈、内存泄漏、线程竞争等问题。

使用Profiler进行性能分析可以确保应用程序运行得更快、更稳定,从而提高用户体验和满意度。

# 2 理解Profiler工具的原理和功能

为了充分利用Profiler工具进行性能分析,开发者需要深入理解Profiler工具的原理和功能。

了解各种性能指标的含义、如何解读Profiler的结果以及如何针对性地优化代码和配置,对于提高Java应用程序性能至关重要。

# 3 选择合适的Profiler工具以优化Java应用性能

市场上有许多Profiler工具可供选择,如Java VisualVM、YourKit、JProfiler以及IntelliJ IDEA Profiler等。

每个工具都有其优缺点和特色功能。开发者应根据自己的需求和应用场景,选择合适的Profiler工具进行性能分析。

同时,不断学习和掌握各种Profiler工具的使用技巧,将有助于更有效地发现和解决Java应用程序中的性能问题。

祝你变得更强!

编辑 (opens new window)
#IntelliJ Profiler#JFR#Java Profiler
上次更新: 2024/10/25
Java基准测试(JMH)
Java调试(JDI与JDWP)

← Java基准测试(JMH) Java调试(JDI与JDWP)→

最近更新
01
Spring Boot版本新特性
09-15
02
Spring框架版本新特性
09-01
03
Spring Boot开发初体验
08-15
更多文章>
Theme by Vdoing | Copyright © 2018-2025 京ICP备2021021832号-2 | MIT License
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式