JVM实战之性能调优[2](线程转储案例认识和分析)

news2024/11/29 2:45:00

文章目录

  • 版权声明
  • 案例1:CPU占用率高问题
    • 问题描述
    • 解决思路
    • 补充内容
  • 案例2:接口响应时间长问题
    • 问题描述
    • 解决思路
    • Arthas trace命令
    • Arthas watch命令
    • 解决问题
  • 案例3:定位偏底层性能问题
    • 问题描述
    • 解决思路:Arthas火焰图
    • 问题解决
  • 案例4:线程被耗尽问题
    • 问题描述
    • 解决思路
    • 问题解决
    • 死锁代码优化

版权声明

  • 本博客的内容基于我个人学习黑马程序员课程的学习笔记整理而成。我特此声明,所有版权属于黑马程序员或相关权利人所有。本博客的目的仅为个人学习和交流之用,并非商业用途。
  • 我在整理学习笔记的过程中尽力确保准确性,但无法保证内容的完整性和时效性。本博客的内容可能会随着时间的推移而过时或需要更新。
  • 若您是黑马程序员或相关权利人,如有任何侵犯版权的地方,请您及时联系我,我将立即予以删除或进行必要的修改。
  • 对于其他读者,请在阅读本博客内容时保持遵守相关法律法规和道德准则,谨慎参考,并自行承担因此产生的风险和责任。
  • 本博客中的部分观点和意见仅代表我个人,不代表黑马程序员的立场。
  • 由于作者精力有限,有关代码的演示和工具的使用和操作,请食用官方的B站JVM教程视频

案例1:CPU占用率高问题

问题描述

  • 监控人员通过prometheus的告警发现CPU占用率一直处于很高的情况,通过top命令看到是由于Java程序引起的,希望能快速定位导致性能问题的代码。

解决思路

  1. 通过top –c 命令找到CPU占用率高的进程,获取进程ID
    在这里插入图片描述
  2. 使用top -p 进程ID单独监控某个进程,按 H H H查看到所有的线程以及线程对应的CPU使用率,找到CPU使用率特别高的线程,并记录线程ID。
    在这里插入图片描述
  3. 使用 jstack 进程ID 命令可以查看到所有线程正在执行的栈信息。使用 jstack 进程ID > 文件名 保存到文件中方便查看。
    在这里插入图片描述
  4. 找到 n i d 线程 I D nid线程ID nid线程ID相同的栈信息,需要将之前记录下的十进制线程号转换成16进制。通过 p r i n t f ′ printf '%x\n' printf 线程ID 命令直接获得16进制下的线程ID
    在这里插入图片描述
  5. 找到栈信息对应的源代码,并分析问题产生原因

补充内容

  • 在定位CPU占用率高的问题时,需要关注的是状态为 R U N N A B L E RUNNABLE RUNNABLE的线程。但实际上,有一些线程执行本地方法时并不会消耗CPU,而只是在等待。但 JVM 仍然会将它们标识成“RUNNABLE”状态。
    在这里插入图片描述

案例2:接口响应时间长问题

问题描述

  • 程序运行过程中,发现有几个接口的响应时间特别长,需要快速定位执行过程中出现性能问题的代码。

解决思路

  • 确定出现性能问题的方法,借助于arthas定位到具体的方法(在方法嵌套比较深的情况下)
    在这里插入图片描述

Arthas trace命令

  • 使用arthas的trace命令,可以展示出整个方法的调用路径以及每一个方法的执行耗时。
  • 语法格式
    trace 类名 方法名
    

⚫ 添加--skipJDKMethod false 参数可以输出JDK核心包中的方法及耗时。
⚫ 添加 #cost > 毫秒值 参数,只会显示耗时超过该毫秒值的调用。
⚫ 添加 –n 数值 参数,最多显示该数值条数的数据。
⚫ 所有监控都结束之后,输入 s t o p stop stop结束监控,重置arthas增强的对象
在这里插入图片描述

Arthas watch命令

  • 使用trace定位到性能较低的方法后,使用watch命令监控该方法,可以获得更为详细的方法信息。
  • 语法格式
    watch 类名 方法名 ‘{params, returnObj}’ ‘#cost>毫秒值' -x 2
    
  • {params, returnObj} 代表打印参数和返回值。
  • -x 代表打印的结果中如果有嵌套(比如对象里有属性),最多只展开2层。允许设置的最大值为4。
    在这里插入图片描述

解决问题

  1. 通过arthas的trace命令,首先找到性能较差的具体方法,如果访问量比较大,建议设置最小的耗时,精确的找到耗时比较高的调用。
  2. 通过watch命令,查看此调用的参数和返回值,关注参数,在开发环境或者测试环境模拟现象,通过debug找到具体的问题根源。
  3. 使用stop命令将所有增强的对象恢复。

案例3:定位偏底层性能问题

问题描述

  • 接口中使用for循环向ArrayList中添加数据,但是最终发现执行时间比较长,需要定位是导致的性能低下的原因
@GetMapping("/profile1")
public void test6() throws InterruptedException {
    ArrayList<Integer> objects = new ArrayList<>();
    for (Integer i = 0; i < 20000000; i++) {
        objects.add(i);
    }
}

解决思路:Arthas火焰图

  • 使用Arthas提供性能火焰图的功能,查看方法的执行耗时
  • 使用arthas的profile命令,生成性能监控的火焰图
    profiler start #1 开始监控方法执行性能
    profiler stop --format html #2 以HTML的方式生成火焰图
    
  • 火焰图中一般找绿色部分Java中栈顶上比较平的部分,很可能就是性能的瓶颈
    在这里插入图片描述
  • 偏底层的性能问题,特别是由于JDK中某些方法被大量调用导致的性能低下,可以使用火焰图非常直观的找到原因

问题解决

  • 案例中是由于创建ArrayList时没有手动指定容量,导致使用默认的容量而在添加对象过程中发生了多次的扩容,扩容需要将原来数组中的元素复制到新的数组中,消耗了大量的时间。
  • 优化后的代码
@GetMapping("/profile2")
   public void test7() throws InterruptedException {
       ArrayList<Integer> objects = new ArrayList<>(20000000);
       for (Integer i = 0; i < 20000000; i++) {
           objects.add(i);
       }
   }

案例4:线程被耗尽问题

问题描述

  • 程序在启动运行一段时间之后,就无法接受任何请求。将程序重启之后继续运行,依然会出现相同的情况。

解决思路

  • 线程耗尽问题,一般是由于执行时间过长,分析方法分成两步:
    1. 检测是否有死锁产生,无法自动解除的死锁会将线程永远阻塞。
    2. 如果没有死锁,再使用案例1的打印线程栈的方法检测线程正在执行的方法,一般大量出现的方法就是慢方法。
  • 死锁:两个或以上的线程因为争夺资源而造成互相等待的现象

问题解决

线程死锁可以通过三种方法定位问题:

  1. jstack -l 进程ID > 文件名将线程栈保存到本地,在文件中搜索deadlock即可找到死锁位置
    在这里插入图片描述
  2. 开发环境中使用visual vm或者Jconsole工具,检测死锁。使用线程快照生成工具查看死锁的根源。生产环境的服务一般不会允许使用这两种工具连接。
    在这里插入图片描述
  3. 使用fastthread自动检测线程问题(Fastthread,是一款在线的AI自动线程问题检测工具,可以提供线程分析报告。通过报告查看是否存在死锁问题。)
    在这里插入图片描述

死锁代码优化

  • 问题代码
private Object obj1 = new Object();
private Object obj2 = new Object();
@GetMapping("/deadlock1")
public String test1() throws InterruptedException {
    synchronized (obj1){
        Thread.sleep(5000);
        synchronized (obj2){
            return "返回成功";
        }
    }
@GetMapping("/deadlock2")
public String test2() throws InterruptedException {
    synchronized (obj2){
        Thread.sleep(5000);
        synchronized (obj1){
            return "返回成功";
        }
    }    
  • 优化代码
private Object obj1 = new Object();
private Object obj2 = new Object();
private Lock lock1 = new ReentrantLock();
private Lock lock2 = new ReentrantLock();

@GetMapping("/deadlock1")
public String test1() throws InterruptedException {
    boolean b1 = lock1.tryLock(1, TimeUnit.SECONDS);
    if(b1){
        try {
            Thread.sleep(5000);
            boolean b2 = lock2.tryLock(1, TimeUnit.SECONDS);
            if(b2){
                try{
                    return "返回成功";
                }
                finally {
                    lock2.unlock();
                }
            }
        }finally {
            lock1.unlock();
        }
    }
    return "处理失败";
}

@GetMapping("/deadlock2")
public String test2() throws InterruptedException {
    boolean b1 = lock2.tryLock(1, TimeUnit.SECONDS);
    if(b1){
        try {
            Thread.sleep(5000);
            boolean b2 = lock1.tryLock(1, TimeUnit.SECONDS);
            if(b2){
                try{
                    return "返回成功";
                }
                finally {
                    lock1.unlock();
                }
            }
        }finally {
            lock2.unlock();
        }
    }
    return "处理失败";
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1560250.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

高级DBA带你处理MySQL客户端程序频繁访问MYSQL数据库并错误链接不释放导致连接数爆满事故实战

高级DBA带你处理MySQL客户端程序频繁访问MYSQL数据库并错误链接不释放导致连接数爆满事故实战 一、生产事故描述 Mysql生产数据库最大连接数爆满&#xff0c;其余客户端也同样拿不到数据库连接&#xff0c;生产异常&#xff0c;数据传输失败&#xff01; 报错如下&#xff1a…

有趣的css - 文字下划线条动画按钮

大家好&#xff0c;我是 Just&#xff0c;这里是「设计师工作日常」&#xff0c;今天分享的是用 css 实现文字下划线条动画按钮。 《有趣的css》系列最新实例通过公众号「设计师工作日常」发布。 目录 整体效果核心代码html 代码css 部分代码 完整代码如下html 页面css 样式页…

【WEEK5】 【DAY5】DML语言【中文版】

2024.3.29 Friday 目录 3.DML语言3.1.外键&#xff08;了解&#xff09;3.1.1.概念3.1.2.作用3.1.3.添加&#xff08;书写&#xff09;外键的几种方法3.1.3.1.创建表时直接在主动引用的表里写&#xff08;被引用的表的被引用的部分&#xff09;3.1.3.2.先创建表后修改表以添加…

近年来,常见5大软件开发项目管理工具

时代进步&#xff0c;技术进步&#xff0c;汇总下近几年5大常用的软件开发项目管理工具。 1、微软项目管理软件 Microsoft Project&#xff08;或MSP&#xff09;是由微软开发销售的项目管理软件程序。软件设计目的在于协助项目经理制定发展计划、为任务分配资源、跟踪进度、管…

目标检测——门牌号数据集

一、重要性及意义 识别自然场景图像中的数字和号码具有极高的重要性和意义&#xff0c;这主要体现在以下几个方面&#xff1a; 实际应用广泛性&#xff1a;自然场景中的数字和号码识别技术在日常生活中有着广泛的应用。例如&#xff0c;在自动驾驶车辆中&#xff0c;准确识别路…

【网站项目】面向社区健康服务的医疗平台

&#x1f64a;作者简介&#xff1a;拥有多年开发工作经验&#xff0c;分享技术代码帮助学生学习&#xff0c;独立完成自己的项目或者毕业设计。 代码可以私聊博主获取。&#x1f339;赠送计算机毕业设计600个选题excel文件&#xff0c;帮助大学选题。赠送开题报告模板&#xff…

【动手学深度学习】深入浅出深度学习之利用神经网络识别螺旋状数据集

目录 &#x1f31e;一、实验目的 &#x1f31e;二、实验准备 &#x1f31e;三、实验内容 &#x1f33c;1. 生成螺旋状数据集 &#x1f33c;2. 打印数据集 &#x1f33c;3. 编程实现 &#x1f33b;仿射层-Affine类 &#x1f33b;传播层-Sigmoid类 &#x1f33b;损失函数…

SSH连接SFTP传输:如何使用libssh库在windows环境下进行(文件、文件夹)传输到远端服务器

配置环境cmake编译libssh如何使用生成的dll与lib文件配置lib 方法一配置lib 方法二配置dll方法一 将dll配置进入环境变量配置dll方法二 在编译过后将dll直接与可执行文件.exe文件放在同一目录下传输文件、文件夹代码&#xff08;适配windows&#xff09; 由于windows上的编译器…

C语言 | Leetcode C语言题解之第2题两数相加

题目&#xff1a; 题解&#xff1a; struct ListNode* addTwoNumbers(struct ListNode* l1, struct ListNode* l2) {struct ListNode *head NULL, *tail NULL;int carry 0;while (l1 || l2) {int n1 l1 ? l1->val : 0;int n2 l2 ? l2->val : 0;int sum n1 n2 …

使用 Spring Email 和 Thymeleaf 技术,向新注册用户发送激活邮件(一)

这篇内容对应"2.1 发送邮件"小节 对应视频&#xff1a;9-发送邮件 视频链接 邮箱设置 需要去邮箱对应的官方客户端软件或网站开启IMAP/SMTP服务或POP3/SMTP服务器 如果不开启&#xff0c;就无法使用第三方用户代理&#xff0c;只能走第官方的电子邮件客户端软件或…

GT收发器第一篇_总体结构介绍

文章目录 前言GT收发器介绍 前言 之前写过一篇简单介绍GT的文章https://blog.csdn.net/m0_56222647/article/details/136730026&#xff0c;可以先通过这篇文章对整体进行简单了解一下。 GT收发器介绍 参考xilinx手册ug476 对于7系列的FPGA&#xff0c;共有3个系列&#xf…

3D检测:从pointnet,voxelnet,pointpillar到centerpoint

记录centerpoint学习笔记。目前被引用1275次&#xff0c;非常高。 地址&#xff1a;Center-Based 3D Object Detection and Tracking (thecvf.com) GitHub - tianweiy/CenterPoint CenterPoint&#xff1a;三维点云目标检测算法梳理及最新进展&#xff08;CVPR2021&#xff…

【Java初阶(七)】接口

❣博主主页: 33的博客❣ ▶文章专栏分类: Java从入门到精通◀ &#x1f69a;我的代码仓库: 33的代码仓库&#x1f69a; 目录 1.前言2.接口2.1语法规则2.2接口使用2.3接口特性2.4实现多个接口2.5接口使用实例2.6Clonable接口和深拷贝 3.Object类3.1对象比较equals方法3.2hashcod…

Vivado使用(1)——综合的约束与策略

目录 一、概述 二、约束与策略 2.1 约束 2.1.1 物理约束 2.1.2 时序约束 2.2 综合策略 2.2.1 flatten_hierarchy 2.2.2 gated_clock_conversion 2.2.3 bufg 2.2.4 fanout_limit 2.2.5 directive 2.2.6 retiming 2.2.7 fsm_extraction 2.2.8 keep_equivalent_regi…

Uibot6.0 (RPA财务机器人师资培训第6天 )发票验真机器人案例实战

类似于小北的这篇博客&#xff1a;Uibot (RPA设计软件&#xff09;Mage AI智能识别&#xff08;发票识别&#xff09;———课前材料五_uibot 添加mageai-CSDN博客https://blog.csdn.net/Zhiyilang/article/details/135591297?spm1001.2014.3001.5501训练网站&#xff1a;泓江…

嵌入式科普(14)指针---这些年嵌入式工程师也不容易理解的词语

目录 一、指针&#xff08;Pointer&#xff09;&#xff1a; 1.1 动态内存管理&#xff1a; 1.2 数组和字符串操作&#xff1a; 1.3 函数参数传递&#xff1a; 1.4 数据结构实现&#xff08;链表&#xff09;&#xff1a; 1.5 实现回调函数&#xff1a; 1.6 提高性能&am…

Day63-LVS四层负载均衡及结合Nginx7层负载均衡实践

Day63-LVS四层负载均衡及结合Nginx7层负载均衡实践 1. LVS&#xff08;Linux Virtual Server&#xff09;介绍2. IPVS&#xff08;LVS&#xff09;发展史3. IPVS软件工作层次图4. LVS技术点小结5. LVS的4模式原理讲解5.1 NAT(Network AddressTranslation)&#xff0c;中文网络地…

纽扣电池CR1632没有电解决方案

使用环境 在使用小米的自拍杆时&#xff0c;发现纽扣电池没有电量了逛了下超市&#xff0c;结果发现都没有卖这个型号的电池&#xff0c;但是下午又要拍照&#xff0c;于是想起了应急的充电方法。声明一下&#xff0c;这个内置电池型号是CR1632&#xff0c;然而市面上&#xff…

vue基础教程(5)——十分钟吃透vue路由router

同学们可以私信我加入学习群&#xff01; 正文开始 前言一、路由概念二、路由使用三、创建路由对应的组件四、给整个项目一个入口总结 前言 前面的文章运行成功后&#xff0c;页面显示如下&#xff1a; 在这个页面中&#xff0c;点击Home和About都会切换右面的页面内容&#…

什么是Redis数据一致性?如何解决?

在系统中缓存最常用的策略是&#xff1a;服务端需要同时维护DB和cache&#xff0c;并且是以DB的结果为准–Cache-Aside Pattern&#xff08;缓存分离模式、旁路缓存&#xff09; 读数据 单纯的读数据是不会产生数据不一致&#xff0c;只有并发下读和写才会存在数据不一致。 写…