JProfiler

JProfiler 是 ej-technologies 出品的 Java 性能分析工具,提供 CPU 分析、内存分析、线程分析、数据库分析四大维度的可视化剖析。适合本地或 CI 环境的深度性能调优,与 Arthas(线上动态诊断)互补。


工具对比

JProfilerArthasjstack / jcmd
分析深度深度(可视化调用树、堆快照)中等(命令行动态观察)基础(快照/统计)
使用场景本地/预发性能调优生产环境无侵入诊断生产快速采集数据
是否需重启否(attach 模式)
界面图形化命令行命令行
费用商业(有试用)免费开源JDK 内置免费

安装与启动模式

本地模式(直接启动 Java 应用)

在 JProfiler 界面:Session → New Session → Profile a local Java application,选择主类或 JAR,JProfiler 以 Agent 方式注入后启动。

Attach 模式(挂载到运行中进程)

Session → Attach to running JVM,选择目标 PID,无需重启应用。适合已运行的 Spring Boot 实例。

远程模式(服务器 / Docker / K8s)

在目标 JVM 启动参数中加入 JProfiler Agent:

# 下载对应平台的 Agent(与本机 JProfiler 版本一致)
# 启动时注入
java -agentpath:/opt/jprofiler/bin/linux-x64/libjprofilerti.so=port=8849 \
     -jar app.jar

JProfiler 客户端:Session → New Session → Profile a remote JVM,填写服务器地址和端口 8849

Docker 远程

# Dockerfile 中预置 Agent
COPY jprofiler/linux-x64 /opt/jprofiler/
 
ENTRYPOINT ["java", \
  "-agentpath:/opt/jprofiler/libjprofilerti.so=port=8849,nowait", \
  "-jar", "app.jar"]
# 映射端口
docker run -p 8849:8849 my-app

IDEA 集成

安装 JProfiler IDEA 插件后,Run/Debug 工具栏出现 JProfiler 按钮,一键在 IDEA 中对当前运行配置启动 JProfiler 分析。


CPU 分析

CPU 分析用于定位热点方法(最耗 CPU 的代码路径)。

采样(Sampling)vs 探针(Instrumentation)

方式原理开销精度
Sampling定期抓取线程栈快照低(推荐首选)统计精度(高频方法可见)
Instrumentation字节码注入,记录每次方法进出高(性能影响显著)精确到每次调用

推荐流程:先 Sampling 定位热点区域 → 再对热点包用 Instrumentation 精确分析。

调用树(Call Tree)

▼ main thread                         100%
  ▼ OrderService.createOrder()          98%
    ▼ InventoryService.checkStock()     85%   ← 热点
      ▼ JdbcTemplate.query()            80%
        ▼ HikariCP.getConnection()      40%   ← 连接池瓶颈
    ▼ PaymentService.charge()           12%
  • 从根节点向下展开,找占比最高的叶子方法
  • 勾选 Filter → Exclude JDK methods 聚焦业务代码
  • 右键方法 → Find in Source:直接在 IDEA 中定位源码

热点视图(Hot Spots)

按自身耗时(不含子方法)排序,直接暴露最慢的具体方法:

Method                           Self Time   Invocations
InventoryDao.countBySkuId()        38%           1,024
StringUtils.formatPrice()          12%          50,320
JsonMapper.serialize()              8%           8,192

内存分析

内存分析用于定位内存泄漏对象分配热点

堆浏览器(Heap Walker)

手动触发堆快照:Memory → Heap Walker → Take Heap Snapshot

对象类           实例数      大小        占比
byte[]           128,340    520 MB     62%
String            98,230    120 MB     14%
HashMap$Entry     42,100     67 MB      8%

通过 References 视图追踪对象的引用链,找到持有大对象的 GC Root:

GC Root → ThreadLocalMap → Entry → UserSession → List<LogRecord> → 泄漏点

分配记录(Allocation Recording)

开启后记录每个对象的分配调用栈,找到在哪段代码分配了大量对象

Session → Start Recording Allocations
... 复现问题场景 ...
Session → Stop Recording Allocations

分配调用树示例:

▼ http-nio-exec-1
  ▼ LogService.buildContext()   42,000 alloc/s
    ▼ String.format()           38,000 alloc/s   ← 频繁创建 String

内存泄漏检测

  1. 记录初始堆快照
  2. 重复执行可疑操作 N 次
  3. 触发 Full GC(Memory → Run GC
  4. 记录第二个堆快照
  5. Compare Snapshots:只有持续增长且 GC 后不释放的对象才是泄漏候选

常见泄漏来源:

  • ThreadLocalremove()
  • 静态集合(static List/Map)无限追加
  • 事件监听器注册后未注销
  • 内部类持有外部类引用

垃圾回收 中的 GC 日志结合分析效果更好。


线程分析

线程历史(Thread History)

时间轴展示每个线程的状态变化:

颜色状态
绿色RUNNABLE(运行中)
红色BLOCKED(等待锁)
橙色WAITING / TIMED_WAITING
蓝色NET(网络 I/O)
灰色SLEEP

红色区域过长 → 锁竞争,点击查看等待哪把锁,持锁线程是谁。

Monitor 使用情况

Threads → Monitors & Locks 查看各 Monitor 的争用热度,定位锁竞争瓶颈:

Lock: com.example.service.OrderService@1a2b3c
  Waiting threads: 12
  Average wait time: 230ms
  Held by: http-nio-exec-5 (currently executing OrderService.updateStatus())

jstack 中死锁检测配合,JProfiler 可可视化查看历史死锁。

线程 Dump

Threads → Thread Dump:等价于 jstack,但可直接在 JProfiler 中高亮标注阻塞线程。


数据库 / JDBC 分析

JProfiler 可拦截 JDBC 调用,统计 SQL 执行情况:

Session → Start Recording JDBC
... 触发业务操作 ...
Session → Stop Recording JDBC

视图:

SQL Statement                              Count   Total Time  Avg Time
SELECT * FROM orders WHERE user_id=?       1,024     8.2s      8ms
UPDATE inventory SET stock=? WHERE id=?    1,024     5.1s      5ms   ← N+1 问题

N+1 SQL 直接暴露(相同语句执行上千次),定位后结合 JPA与Hibernate 的批量查询或 JOIN 优化。


典型排查场景

场景 1:接口 P99 延迟高

  1. Attach 到目标进程,开启 CPU Sampling
  2. 用压测工具(JMeter)模拟负载
  3. 在 Call Tree 中找调用链最慢的分支
  4. 切换 Instrumentation 对热点包精确计时
  5. 定位到 InventoryDao.checkStock() 无索引全表扫描 → 加索引

场景 2:内存持续增长,Full GC 后不回落

  1. Attach,间隔 10 分钟抓两次 Heap Snapshot
  2. Compare:找增量最大的对象类型
  3. Heap Walker → References:追溯 GC Root 引用链
  4. 发现 static ConcurrentHashMap<String, Session> 未清理过期 Session
  5. 添加定时清理逻辑

场景 3:请求偶发卡顿(无 CPU 耗用)

  1. Thread History 查看卡顿时间窗口
  2. 所有请求线程均为橙色(WAITING)
  3. Monitor 视图:等待 HikariPoolgetConnection()
  4. 连接池满,扩大 maximumPoolSize 或排查慢 SQL 导致连接不归还

JVM 参数与 GC 分析

JVM → GC Activity 面板展示:

  • GC 事件时间轴(Minor GC / Full GC)
  • 各代内存变化曲线
  • GC 停顿时间

配合 性能调优 中的 JVM 参数调整,验证调整效果。


常用配置技巧

过滤器(Filter)

只记录业务包,排除 JDK / 框架噪音:

Settings → Filter Settings
    Include: com.example.*
    Exclude: org.springframework.*, com.sun.*, java.*

快照保存与对比

File → Save Snapshot (.jps)
File → Open Snapshot
Compare Snapshots(内存视图支持差量对比)

Trigger(自动触发快照)

在特定条件下自动保存快照(如 GC 后内存超阈值、线程 Deadlock 检测到时):

Session → Triggers → Add Trigger
    Condition: Memory > 80%
    Action: Save Heap Snapshot

相关链接

  • JMeter — 负载与性能压测,与本工具联调定位热点
  • Arthas — 线上无侵入动态诊断,与 JProfiler 互补
  • IDEA — JProfiler IDEA 插件一键启动分析
  • jstack — 命令行线程快照,轻量替代
  • jcmd — JVM 多合一诊断命令
  • JVM — 内存模型与 GC 机制背景
  • 垃圾回收 — GC 算法,配合内存分析结果调优
  • 性能调优 — JVM 参数与连接池调优实践