【Jvm】性能调优(拓展)Jprofiler如何监控和解决死锁、内存泄露问题

文章目录

    • Jprofiler简介
    • 1.安装及IDEA集成Jprofiler
    • 2.如何监控并解决死锁
    • 3.如何监控及解决内存泄露(重点)
    • 4.总结
    • 5.后话

Jprofiler简介

  • Jprofilers是针对Java开发的性能分析工具(免费试用10天), 可以对Java程序的内存,CPU,线程,GC,锁等进行监控和分析,

1.安装及IDEA集成Jprofiler

本人IDEA版本是2020.2.2,选择的Jprofiler版本是12.0(早期的版本是纯英文的,12.0支持中文,安装主要考虑是否与IDEA插件兼容即可)

  1. 进入Jprofiler官网下载 -> Jprofiler 版本这边建议选择最新的或者次新的(前提是你的IEDA版本也比较新)

  2. 打开IDEA->File->settings->plugins->marketplace->搜索 Jprofiler
    在这里插入图片描述

  3. 插件安装后, 在IDEA工具栏找到如图所示的两个图标,点击箭头指的那个,进行路径配置,让插件能找到第1步中下载好的Jprofiler:
    在这里插入图片描述

    • 选中后然后同意安装协议, 一路next确认就好了,最后选试用10天激活,如果你有秘钥可以选永久激活,至此就安装好了,然后可以通过该按钮启动应用

      在这里插入图片描述

    1. 启动后就可以获取到启动应用的各种信息了, 也可以连接远程服务器上的java应用,或者通过dump出来的文件分析等:

      在这里插入图片描述

2.如何监控并解决死锁

public static void main(String[] args) {Object a = new Object();Object b = new Object();new Thread(()->{synchronized (a){try {System.out.println("已获取到a锁,尝试获取b锁===>");Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}synchronized (b){System.out.println("尝试获取b锁...");}}}).start();new Thread(()->{synchronized (b){try {System.out.println("<===已获取到b锁,尝试获取a锁");Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}synchronized (a){System.out.println("尝试获取a锁...");}}}).start();}

通过Jprofiler启动这段代码,然后可以在锁菜单界面直接看到当前锁的状态图:
在这里插入图片描述

然后可以在当前Monitor监视器设置一个观察阈值, 如果项目中的锁比较多, 可以把超过一定时间的锁给筛选出来, 进一步观察是否死锁, 因为有些长时间阻塞的锁`也可能是 饿锁
在这里插入图片描述

然后针对筛选出来的几个可能是死锁的进行深入分析, 首先可以看到这些锁的类型是处于阻塞的, 然后鼠标右键任意一个锁上面 选择在堆遍历器中显式所选内容:
在这里插入图片描述
然后在对堆遍历器中点击图表, 就可以看到这个锁所在的代码位置, 然后 看一看代码就知道到底有没有死锁,还是饿锁了
在这里插入图片描述

通常来说产生死锁的原因主要有:

  1. 没有设置锁的失效时间, 然后代码里可能因为异常没有处理, 锁没有在finaly代码块中释放导致其它线程无法获取锁而陷入等待

  2. 锁互相竞争(类似上图这种) ,线程1持有A锁尝试获取B锁, 线程2持有B锁尝试获取A锁, 谁也不让谁, 互相干等着。 这种情况要注意加锁的顺序, 让线程1是先获得了A锁,再去获取B锁, 然后线程2去尝试获取A锁,再获取B锁, 按这样的顺序就不会产生死锁.

  3. 由线程优先级产生的饿锁,即高优先级线程一直占着资源不放而导致其他线程得不到执行, 饿锁不算死锁,但也要引起重视,否则同样会造成资源浪费, 可以通过JUC提供的公平锁解决.

——>按照上面的思路,去排查对应的代码,基本上死锁都能被解决.

3.如何监控及解决内存泄露(重点)

内存泄漏相对于死锁和OOM会比较难定位,而且对整个应用的危害程度比较大, 一旦发生内存泄漏,可能会导致整个应用不可用.

  • 内存泄漏可以通过JDK自带的jconsole或者jvisovm都可以监控到,这里演示下通过Jprofiler如何监控内存泄漏.

  • 通常情况下,内存泄漏会拖垮整个应用,如果应用突然不可用了, 且网络正常. 可以服务器查看应用日志, 如果看到有OOM,可以初步怀疑有内存泄漏发生, 对于比较明显 或者 比较短的时间内产生的内存泄漏, 可以通过本地IDEA直连Jprofile启动应用的方式进行监控 ,对于在特定场景下才会发生的,可以加上VM参数: -XXHeapdump重启线上应用, 以便在下次内存泄漏OOM时,导出dump日志,然后导入Jprofile进行分析. 这里我以直连本地的方式进行演示(偷个懒)

public class Test {private final static ThreadLocal<List<String>> threadLocal = new ThreadLocal<>();private final static List<String> list = new ArrayList<>();public static void main(String[] args) throws InterruptedException {ExecutorService executorService = Executors.newSingleThreadExecutor();executorService.execute(()->{while (true){for (int i = 0; i < 1000000; i++) {list.add("oom");if (i%100==0){threadLocal.set(list);}}//让过程慢一点,留点时间去分析,否则OOM之后与Jprofiler的连接就断开了try {Thread.sleep(5000);} catch (InterruptedException e) {e.printStackTrace();}}});}
}

为了尽快的看到内存泄漏又能不中断与jprofiler的连接指定最大堆为1024M(-Xmx1024m ) , 以保证上面程序运行久一点, 不因为OOM中断影响分析
在这里插入图片描述
(上图是程序运行了很久之后)

  • 用IDEA的Jprofiler插件启动Jprofiler, 切换到遥测->内存界面, 内存使用量每增长一段时间后, 手动点击一次运行GC, 观察每次GC后已使用内存部分(下图中蓝色部分), 发现每次GC之后,已使用的内存变得越来越多, 如此积累下去, 直到已使用内存超过最大堆大小,应用就无法再创建对象, 然后疯狂触发GC, 但GC后又没有效果, 最终GC过载, CPU和内存资源被榨干,服务处于不可用状态.

    一句话: 观察前一次GC 和 当前GC后 剩余已用内存 是否处于 不断递增之中,如果是 ,则极有可能发生了内存泄漏.

在这里插入图片描述
在这里插入图片描述
通过线上服务不可用监控到的数据, 几乎可以确认是发生了内存泄漏,下面开始排查,到底是哪里发生了内存泄漏?写了什么禽兽代码让内存泄漏了???

  1. 第一步:通过Jprofiler连接到本地或者远程JVM(考虑到安全问题,可以用远程dump的日志导入Jprofiler)

  2. 第二步:点击实时内存菜单下的所有对象, 然后点击标记当前对象, 然后持续观察实例 计数列,相差列,大小列变化

可以从以下几个线索去缩小范围:

  1. 可能发生内存泄漏的一般有 char[],String,Map,List,Object[] 等数据,可以重点去看看

  2. 占据大量内存空间 或是 实例计数超大的

    一般会导致内存泄漏且影响到服务正常吞吐的, 大小列的值都不会太小,毕竟一个应用的最大堆至少也会指定/默认在256Mb以上,像这种几百kb级别的,即便在持续增长,想要让系统不可用,也得积累很久很久

  3. 多次点击运行GC,观察每次GC后剩余的大小,如果大小列的值增长很快,但GC后仍剩余很大,可以怀疑此处可能有内存泄漏

    比如下图被我框了的地方, GC前有400多Mb, GC后仍有186MB剩余, 整个堆区在GC后剩余的总垃圾也不过189MB, 这玩意就独占鳌头186Mb,回收不掉, 隔一阵子再点GC,GC后这个值比186MB还大,再次印证该类很可能存在内存泄漏)

    在这里插入图片描述

    通过上面3种排查方式,逐步缩小排查范围,目前看下来就只有char[],String,Object[]三种类型的数据可能存在内存泄露

  • 第三步: 选中可疑项,点击鼠标右键,选择在堆遍历器中显式

在这里插入图片描述

在打开的新界面中,点击最大对象, 然后选中保留大小最大的(有的时候有好几个都挺大的,只能一一尝试,因为保留大小偏大的一般都可能导致内存泄漏),然后点击鼠标右键,使用选中对象

在这里插入图片描述
然后选择传入引用,点击确定
在这里插入图片描述
在下图中的界面,可以先展开树形结构的数据看一下,这个Oject[]底下是什么东西, 一般来说如果点开是大公司打头的包名,基本可以直接跳过不用看了,因为一般大公司的产品不大会出现内存泄漏,发布之前他们应该也有测过了.

  • 如果看了下包名,是自己应用的包名,就可以继续排查,点击在图表中显示
    在这里插入图片描述

在弹出的新页面中选中上一步中看到的ArrayList对象,点击显示到GC根的路径:

在这里插入图片描述
在这里插入图片描述
然后可以点开+号,瞅瞅, 基本上到这一步,就能确认到发生内存泄漏的代码所在的包名+类名了, 然后重点去排查这段代码即可
在这里插入图片描述
原因 :

  • 因为ThreadLocal持有List<String>,然后ThreadLocal并没有remove(),导致List<String>被强引用,无法被GC,致使内存泄漏.

4.总结

  1. 如果没有Jprofiler这类工具, 在生产环境发生内存泄漏, 去一行一行review所有代码是不现实的, 通过此工具我们可以在较短的时间内定位到导致内存泄漏出现的代码位置, 然后review该位置的代码即可.

  2. 内存泄漏的难的主要是定位, 解决起来一般比较简单, 重启生产环境应用,让服务恢复正常, 然后在把导致内存泄漏的代码优化(该释放的释放,强引用显示置为为null...),改好之后测试并重新发布即可解决.

5.后话

当这些问题出现在生产环境时,一般都会带来严重的损失,而且排查和分析起来难度非常大, 在养成良好编码习惯, 尽量去规避死锁,内存溢出,及内存泄漏, 防患于未然是最好的

  • 多学点监控和解决方式, 或许有一天还真能派上用场.像这类低频使用的知识, 最好能总结一遍,留下文档,下次再碰到时,可以快速回忆,

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【AIGC】Stable Diffusion的生成参数入门

Stable Diffusion 的生成参数是用来控制图像生成过程的重要设置&#xff0c;下面是一些常见的生成参数及其详解 1、采样器&#xff0c;关于采样器的选择参照作者的上一篇文章 2、采样步数&#xff08;Sampling Steps&#xff09;是指在生成图像时模型执行的总步数&#xff0c…

计算机网络——18无连接传输UDP

无连接传输UDP UDP “尽力而为的”服务&#xff0c;报文段可能 丢失送到应用进程的报文段乱序 无连接 UDP发送端和接收端之间没有握手每个UDP报文段都被独立的处理 UDP被用于 流媒体DNSSNMP 在UDP上实现可靠传输 在应用层增加可靠性应用特定的差错格式 UDP&#xff1a;用户…

unity学习(19)——客户端与服务器合力完成注册功能(1)入门准备

逆向服务器用了三天的时间&#xff0c;但此时觉得一切都值&#xff0c;又可以继续学习了。 服务器中登录请求和注册请求由command变量进行区分&#xff0c;上一层的type变量都是login。 public void process(Session session, SocketModel model) {switch (model.Command){ca…

C++学习:stack

1.stack的定义和结构 stack是一种后进先出(LIF0)的数据结构&#xff0c;使用前需要包含头文件,stack提供了一组函数来操作和访问元素&#xff0c;但它的功能相对较简单。stack的定义和结构如下(仅作了解即可): template<class T, class (ontainer deque<T>> cla…

CTFshow web(php命令执行 68-71)

web68 还是那句话&#xff0c;没看到flag在哪&#xff0c;那就优先找到flag位置 这里cvar_dump(scandir("/")); 直接输出根目录的位置&#xff0c;然后查看源代码&#xff0c;发现flag位置为flag.txt 知道flag在根目录下面的flag.txt直接访问就好了 cinclude(/flag…

element 表单提交图片(表单上传图片)

文章目录 使用场景页面效果前端代码 使用场景 vue2 element 表单提交图片   1.点击【上传图片】按钮择本地图片&#xff08;只能选择一张图片&#xff09;后。   2.点击图片&#xff0c;支持放大查看。   3.点击【保存】按钮&#xff0c;提交表单。 页面效果 前端代码…

K8s服务发现组件之CoreDNS/NodeLocalDNS /kubeDNS

1 coredns 1.1 概述 1.1.1 什么是CoreDNS CoreDNS 是一个灵活可扩展的 DNS 服务器&#xff0c;可以作为 Kubernetes 集群 DNS&#xff0c;在Kubernetes1.12版本之后成为了默认的DNS服务。 与 Kubernetes 一样&#xff0c;CoreDNS 项目由 CNCF 托管。 coredns在K8S中的用途,…

机器人常用传感器分类及一般性要求

机器人传感器的分类 传感技术是先进机器人的三大要素&#xff08;感知、决策和动作&#xff09;之一。根据用途不同&#xff0c;机器人传感器可以分为两大类&#xff1a;用于检测机器人自身状态的内部传感器和用于检测机器人相关环境参数的外部传感器。 内部传感器 内部传感…

Allegro172版本如何用自带功能改变过孔网络属性操作指导

Allegro172版本如何用自带功能改变过孔网络属性操作指导 在用Allegro做PCB设计的时候,时常会需要将过孔的网络进行变更,可以将原来的过孔删除,再重新打一个,这种方法难免会繁琐一些。 当然我们可以借助skill工具来完成更换过孔网络的更改,除此之外,Allegro自带的功能完成…

【.NET Core】深入理解async 和 await 理解

【.NET Core】深入理解async 和 await 理解 文章目录 【.NET Core】深入理解async 和 await 理解一、概述二、async异步执行机制理解三、async与await应用3.1 async与await简单应用3.2 带有返回值async与await应用 四、async和await中常见问题总结4.1 当方法用async标识时&…

Editing While Playing 使用 Easyx 开发的 RPG 地图编辑器 tilemap eaitor

AWSD移动画布 鼠标右键长按拖拽 鼠标左键长按绘制 可以边拖拽边移动画布边绘制。 F1 导出 DLC F2 导入DLC author: 民用级脑的研发记录 1309602336qq.com 开发环境&#xff1a; 内置 easyx 的 devc 5.11 或者 VS 2022 TDM GCC 4.9.2 64-bit c11及以上都可运行 windows 环境运行…

JS加密解密之JS广告漂浮代码分析

前言 之前有个客户要求帮忙复刻一份广告漂浮代码&#xff0c;我看了下&#xff0c;目标站的广告代码是通过了JS加密后的&#xff0c;经过我解密还原后分析了一下该代码的作用如下。 ;var _0xodDddd,_0xodD_[_0xodD],_0x1d02[_0xodD,\x73\x54\x69\x6d\x65,\x6c\x6f\x61\x64\x5…

计算机专业必看的几部电影

计算机专业必看的几部电影 计算机专业必看的几部电影&#xff0c;就像一场精彩的编程盛宴&#xff01;《黑客帝国》让你穿越虚拟世界&#xff0c;感受高科技的魅力&#xff1b;《社交网络》揭示了互联网巨头的创业之路&#xff0c;《源代码》带你穿越时间解救世界&#xff0c;…

PAM | 账户安全 | 管理

PAM PAM&#xff08;Pluggable Authentication Modules&#xff0c;可插入式身份验证模块&#xff09;是一个灵活的身份验证系统&#xff0c;允许我们通过配置和组合各种模块来实现不同的身份验证策略。 在 Linux 或类 Unix 系统中&#xff0c;常见的 PAM 模块包括以下几种类…

Ansible file文件模块 设置文件的属性,比如创建文件、创建链接文件、删除文件

目录 语法创建目录创建链接文件删除文件 每个值的属性 语法 创建目录 ansible slave -m file -a path/data/app statedirectory path/data/app # 定义创建路径 statedirectory # 如果目录不存在就创建目录这就是创建目录成功之后的回显 可以看到&#xff0c;已经打印出目录a…

MySQL的基础架构

文章目录 前言MySQL的基础架构总结 前言 你使用 MySQL 开发&#xff0c;你知道 MySQL 的基础架构吗&#xff1f;本文带你来入门MySQL 的基础架构 MySQL的基础架构 MySQL 是我们经常使用到的数据库。它的基础架构分为 server 层与存储引擎层。 server 层&#xff1a;用于存储…

推荐彩虹知识付费商城免授权7.0源码

彩虹知识付费商城免授权7.0源码&#xff0c;最低配置环境 PHP7.2 1、上传源码到网站根目录&#xff0c;导入数据库文件&#xff1a;xydai.sql 2、修改数据库配置文件&#xff1a;/config.php 3、后台&#xff1a;/admin 账号&#xff1a;admin 密码&#xff1a;123456 4、前…

【Jvm】类加载机制(Class Loading Mechanism)原理及应用场景

文章目录 Jvm基本组成一.什么是JVM类的加载二.类的生命周期阶段1&#xff1a;加载阶段2&#xff1a;验证阶段3&#xff1a;准备阶段4&#xff1a;解析阶段5&#xff1a;初始化 三.类初始化时机四.类加载器1.引导类加载器&#xff08;Bootstrap Class Loader&#xff09;2.拓展类…

第九篇:node静态文件服务(中间件)

&#x1f3ac; 江城开朗的豌豆&#xff1a;个人主页 &#x1f525; 个人专栏 :《 VUE 》 《 javaScript 》 &#x1f4dd; 个人网站 :《 江城开朗的豌豆&#x1fadb; 》 ⛺️ 生活的理想&#xff0c;就是为了理想的生活 ! &#x1f4d8; 引言&#xff1a; 当今互联网时代&am…

[AIGC] 利用 ChatGpt 深入理解 Java 虚拟机(JVM)的内存分布

深入理解 Java 虚拟机&#xff08;JVM&#xff09;的内存分布 Java 虚拟机&#xff08;JVM&#xff09;是 Java 编程语言的核心运行环境&#xff0c;它负责解释和执行 Java 字节码。在 JVM 中&#xff0c;内存被划分为几个不同的区域&#xff0c;每个区域都有特定的用途。了解…