[最佳实践] Java线程栈分析 - CPU利用率持续升高

本文涉及的产品
日志服务 SLS,月写入数据量 50GB 1个月
简介: 使用应用诊断分析平台ATP的Java线程栈分析功能,诊断CPU利用率持续升高问题

Java线程栈分析 - CPU利用率持续升高

异常现象

某日接到业务同学反馈异常如下:

1.业务放量过程中,cpu持续升高,不清楚具体的原因2.系统代码主要在等待下游返回结果,本地并没有复杂的处理逻辑

线程栈分析

业务同学保留了现场的jstack log(线程栈日志)。上传线程栈日志并通过ATP线程栈分析。打开方法热度视图,它会聚合出那一刻Java进程内所有线程调用方法的热度信息:

image.png

选择最热的方法(即最深的那条柱):

image.png

根据方法名可以看出最热的方法是反序列化,序列化过程中会使用URLClassLoader加载类:


Hessian2Input.readObject();
...
ClassLoader.loadClass();
URLClassLoader.loadClass();
URLClassPath.getResource();
URLClassPath.getNextLoader();
URLClassPath.getLoader();

URLClassLoaer里面有个ucp(URLClassPath),它记录了当前URLClassLoader类加载器加载了哪些jar包,在类加载过程中,它会遍历所有jar包,然后逐个打开jar包并查找里面是否存在期望的类。再结合业务同学的反馈,大概有500多个jar包,所以根据线程栈分析得出的初步猜测是:在反序列化过程中遇到未加载的类,然后触发URLClassloader从500多个jar包中遍历查找类,这个查找过程导致了CPU利用率持续升高。

根据上述的栈名称,我们从jstack log中找到对应线程:

image.png

可以看到类加载过程中有三个地方加锁了,查看这些锁:

image.pngimage.png

会发现实际上有两把锁,其中一个被递归加锁,更重要的是锁的持有者都是1068线程,另外没有其他线程在等待该锁,说明锁没有竞争,类查找过程仅1068一个线程在进行。


分析结论

所以我们可以更进一步得知,只有一个线程在执行高频的jar包遍历寻找类操作。根据这个猜测的结论,只要类找到,或者说反序列化结束,CPU利用率就应该会下降。和业务同学反馈后得知,序列化在持续进行。这也顺便验证了我们的猜测,因为只有反序列化在持续进行,CPU利用率才会持续上涨。

将这个猜测反馈给业务同学,他们从日志中发现,确实是因为有个类一直找不到,然后每次都在反序列化的时候在重新找,找不到也只会打个日志。到此,分析基本就结束了,剩下的工作是业务同学优化代码,解决该类找不到的问题。

image.png


欢迎投稿「应用诊断分析平台ATP」问题诊断分析的案例

相关实践学习
日志服务之使用Nginx模式采集日志
本文介绍如何通过日志服务控制台创建Nginx模式的Logtail配置快速采集Nginx日志并进行多维度分析。
目录
相关文章
|
5天前
线程CPU异常定位分析
【10月更文挑战第3天】 开发过程中会出现一些CPU异常升高的问题,想要定位到具体的位置就需要一系列的分析,记录一些分析手段。
24 0
|
8天前
|
Java 关系型数据库 MySQL
如何用java的虚拟线程连接数据库
本文介绍了如何使用Java虚拟线程连接数据库,包括设置JDK版本、创建虚拟线程的方法和使用虚拟线程连接MySQL数据库的示例代码。
21 6
如何用java的虚拟线程连接数据库
|
5天前
|
监控 Java Linux
Java 性能调优:调整 GC 线程以获得最佳结果
Java 性能调优:调整 GC 线程以获得最佳结果
35 11
|
1天前
|
并行计算 Java 调度
深入理解Java中的多线程编程
【10月更文挑战第6天】 本文将探讨Java中多线程编程的基本概念、实现方式及其在实际项目中的应用。通过详细的示例和解释,读者能够掌握如何在Java中有效地使用多线程来提高程序的性能和响应能力。
5 1
|
2天前
|
Java 开发者
在 Java 多线程编程中,Lock 接口正逐渐取代传统的 `synchronized` 关键字,成为高手们的首选
【10月更文挑战第6天】在 Java 多线程编程中,Lock 接口正逐渐取代传统的 `synchronized` 关键字,成为高手们的首选。相比 `synchronized`,Lock 提供了更灵活强大的线程同步机制,包括可中断等待、超时等待、重入锁及读写锁等高级特性,极大提升了多线程应用的性能和可靠性。通过示例对比,可以看出 Lock 接口通过 `lock()` 和 `unlock()` 明确管理锁的获取和释放,避免死锁风险,并支持公平锁选择和条件变量,使其在高并发场景下更具优势。掌握 Lock 接口将助力开发者构建更高效、可靠的多线程应用。
8 2
|
3天前
|
监控 Java 调度
Java有哪几种方式创建线程?
本文详细介绍了Java中创建线程的四种主要方法:继承`Thread`类、实现`Runnable`接口、实现`Callable`接口配合`Future`,以及使用`Executor`框架。每种方法都有其独特特性和适用场景。通过示例代码和特点分析,帮助开发者根据具体需求选择合适的方式。
12 3
|
8天前
|
Java 调度
Java一个线程的生命周期详解
Java中,一个线程的生命周期分为五个阶段:NEW(新建),RUNNABLE(可运行),BLOCKED(阻塞),WAITING(等待),TERMINATED(终止)。线程创建后处于新建状态,调用start方法进入可运行状态,执行中可能因等待资源进入阻塞或等待状态,正常完成或异常终止后进入终止状态。各状态间可相互转换,构成线程的生命周期。
|
8天前
|
Java API 调度
Java 多线程编程详解
《Java多线程编程详解》深入浅出地讲解了Java平台下的多线程核心概念、API使用及最佳实践。从基础理论到实战案例,本书帮助读者掌握并发编程技巧,提升软件开发中的效率与性能,是Java开发者不可或缺的参考指南。
|
4天前
|
Java 数据处理 数据库
Java多线程的理解和应用场景
Java多线程的理解和应用场景
17 1
|
5天前
|
安全 Java 开发者
在多线程编程中,确保数据一致性与防止竞态条件至关重要。Java提供了多种线程同步机制
【10月更文挑战第3天】在多线程编程中,确保数据一致性与防止竞态条件至关重要。Java提供了多种线程同步机制,如`synchronized`关键字、`Lock`接口及其实现类(如`ReentrantLock`),还有原子变量(如`AtomicInteger`)。这些工具可以帮助开发者避免数据不一致、死锁和活锁等问题。通过合理选择和使用这些机制,可以有效管理并发,确保程序稳定运行。例如,`synchronized`可确保同一时间只有一个线程访问共享资源;`Lock`提供更灵活的锁定方式;原子变量则利用硬件指令实现无锁操作。
10 2