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

文章目录

  • 版权声明
  • 案例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.mfbz.cn/a/497897.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Siemens S7-1500TCPU 运动机构系统功能简介

目录 引言&#xff1a; 1.0 术语定义 2.0 基本知识 2.1 运动系统工艺对象 2.2 坐标系与标架 3.0 运动机构系统类型 3.1 直角坐标型 3.2 轮腿型 3.3 平面关节型 3.4 关节型 3.5 并联型 3.6 圆柱坐标型 3.7 三轴型 4.0 运动系统的运动 4.1 运动类型 4.1.1 线性运动…

ArcGIS Pro横向水平图例

终于知道ArcGIS Pro怎么调横向图例了&#xff01; 简单的像0一样 旋转&#xff0c;左转右转随便转 然后调整图例项间距就可以了&#xff0c;参数太多就随便试&#xff0c;总有一款适合你&#xff01; 要调整长度&#xff0c;就调整图例块的大小。完美&#xff01; 好不容易…

win10+cuda11.8+cudnn8.6.0安装

目录 一、NVIDIA 驱动程序下载 二、cuda11.8下载 三、cudnn8.6.0下载 四、确认cuda和cudnn是否安装成功 一、NVIDIA 驱动程序下载 1、查看显卡类型&#xff1a;连续按下CTRLALTDELETE -> 选择任务管理器 -> 性能 -> GPU -> 右上角 2、下载地址&#xff1a;官方…

阿里云CentOS7安装Hadoop3伪分布式

ECS准备 开通阿里云ECS 略 控制台设置密码 连接ECS 远程连接工具连接阿里云ECS实例&#xff0c;这里远程连接工具使用xshell 根据提示接受密钥 根据提示写用户名和密码 用户名&#xff1a;root 密码&#xff1a;在控制台设置的密码 修改主机名 将主机名从localhost改为需要…

iPhone用GPT替代Siri

shigen坚持更新文章的博客写手&#xff0c;擅长Java、python、vue、shell等编程语言和各种应用程序、脚本的开发。记录成长&#xff0c;分享认知&#xff0c;留住感动。 个人IP&#xff1a;shigen 前一段时间&#xff0c;因为iCloud协议的更新&#xff0c;我的云盘空间无法正常…

骗子查询系统源码

源码简介 小权云黑管理系统 V1.0 功能如下&#xff1a; 1.添加骗子&#xff0c;查询骗子 2.可添加团队后台方便审核用 3.在线反馈留言系统 4.前台提交骗子&#xff0c;后台需要审核才能过 5.后台使用光年UI界面 6.新增导航列表&#xff0c;可给网站添加导航友链 7.可添加云黑类…

Nginx第三方模块---nginx-sticky-module的使用(基于cookie的会话保持)

目录 Nginx和Sticky介绍 编译安装sticky的nginx环境 安装过程碰到的问题和编译安装过程遇到的错误&#xff1a; &#xff08;1&#xff09;第一个错误&#xff1a;修改源代码ngx_http_sticky_module.c &#xff08;2&#xff09;第二个错误&#xff1a;修改源代码ngx_http_s…

课堂练习——4、实验环境练习

任务描述 本关任务&#xff1a;修改 Linux 0.11 内核程序&#xff0c;将系统启动时显示的字符串由原来的Partition table ok.变为Hello, world!。 通过本关任务&#xff0c;可以熟悉 Linux 0.11 内核实验环境&#xff0c;掌握内核程序的编辑、编译和测试方法。 相关知识 为了…

Java基础(概念,环境,包,IDEA,)

目录 什么是Java 什么是程序 Java简史 Java技术体系平台 Java语言的特点 搭建环境 搭建Java开发环境 理解三个核心概念 安装Java环境 配置环境变量 编写第一段代码&#xff1a;HelloWorld 创建源代码文件 编写代码 保存文件 编译Java程序 运行程序 查看输出 编…

C#String的remove的用法

string test "abc";string temp test;temp.Remove(0, 1);temp temp.Remove(0, 1);Console.WriteLine(temp);Console.WriteLine(test);执行结果

前端基础知识html

一.基础标签 1.<h1>-<h6>:定义标题&#xff0c;h最大&#xff0c;h最小 2.<font>&#xff1a;定义文本的字体&#xff0c;尺寸&#xff0c;颜色 3.<b>&#xff1a;定义粗体文本 4.<i>&#xff1a;定义斜体文本 5.<u>&#xff1a;定义文本下…

MGRE实验

MGRE实验 1、实验要求 2、实验分析 IP地址分类 私网IP&#xff1a;192.168.1.0等隧道IP&#xff1a;192.168.5.0和192.168.6.0公网IP&#xff1a;15.0.0.1等 配置IP地址 配置acl访问控制列表 用于将内部网络中的私有IP地址转换为公共IP地址&#xff0c;以实现与外部网络的通…

[flink 实时流基础系列]揭开flink的什么面纱基础一

Apache Flink 是一个框架和分布式处理引擎&#xff0c;用于在无边界和有边界数据流上进行有状态的计算。Flink 能在所有常见集群环境中运行&#xff0c;并能以内存速度和任意规模进行计算。 文章目录 0. 处理无界和有界数据无界流有界流 1. Flink程序和数据流图2. 为什么一定要…

多焦点图像融合文献学习(一)

本文介绍的是一篇明为"A convolutional neural network-based conditional random field model for structured multi-focus image fusion robust to noise."的文献&#xff0c;主要包括文献的摘要、前言摘选、主要贡献、网络结构、实验结果及结论等方面。 文献名称摘…

浅谈Mysql(三)——MySQL/InnoDB 事务隔离级别分享

主要内容 事务特性 • 原子性&#xff08;Atomicity • 一致性&#xff08;Consistency&#xff09; • 隔离性&#xff08;Isolation&#xff09; • 持久性&#xff08;Durability 日志体系-更新语句的执行过程 • redo log • binlog 事务隔离 隔离性遇见的问题 隔离级…

Golang-Gin光速入门

安装 go get -u github.com/gin-gonic/gin初始化项目并启动服务 go mod init gin-project package mainimport "github.com/gin-gonic/gin"func main() {r : gin.Default()r.GET("/ping", func(c *gin.Context) {c.JSON(200, gin.H{"message"…

2.11 Python关键字(保留字)

Python关键字&#xff08;保留字&#xff09;一览表 保留字是Python 语言中一些已经被赋予特定意义的单词&#xff0c;这就要求开发者在开发程序时&#xff0c;不能用这些保留字作为标识符给变量、函数、类、模板以及其他对象命名。 Python 包含的保留字可以执行如下命令进行…

GRE VPN——配置实验

1&#xff0c;按照图示配置IP地址 r1&#xff1a; r2&#xff1a; r3&#xff1a; 2&#xff0c;在R1和R3配置默认路由使公网区域互通 [R1]ip route-static 0.0.0.0 0 100.1.1.2 R3]ip route-static 0.0.0.0 0 100.2.2.2 3&#xff0c;在R1和R3上配置GRE VPN&#xff0c;使…

追踪Aurora(欧若拉)勒索病毒,Emsisoft更新解密工具

Aurora(欧若拉)勒索病毒首次出现于2018年7月左右&#xff0c;加密后的文件后缀为Aurora&#xff0c;2018年11月&#xff0c;此勒索病毒的一款变种样本&#xff0c;加密后的文件后缀为Zorro&#xff0c;同时发现了此勒索病毒的一个BTC钱包地址&#xff1a; 18sj1xr86c3YHK44Mj2…

第二证券今日投资参考:低空经济迎利好 自动驾驶商业化提速

昨日&#xff0c;两市股指盘中弱势震动&#xff0c;午后加快下探&#xff0c;沪指失守3000点大关&#xff0c;深成指、创业板指跌超2%&#xff1b;到收盘&#xff0c;沪指跌1.26%报2993.14点&#xff0c;深成指跌2.4%报9222.47点&#xff0c;创业板指跌2.81%报1789.82点&#x…