【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插件兼容即可)
-
进入Jprofiler官网下载 -> Jprofiler 版本这边建议选择
最新的或者次新的
(前提是你的IEDA版本也比较新) -
打开IDEA->File->settings->plugins->marketplace->搜索 Jprofiler
-
插件安装后, 在IDEA工具栏找到如图所示的两个图标,点击箭头指的那个,进行
路径配置
,让插件能找到第1步中下载好的Jprofiler:
-
选中后然后同意安装协议,
一路next确认就好了
,最后选试用10天激活
,如果你有秘钥可以选永久激活,至此就安装好了,然后可以通过该按钮启动应用
-
启动后就可以获取到启动应用的各种信息了, 也可以
连接远程服务器上的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监视器
设置一个观察阈值, 如果项目中的锁比较多, 可以把超过一定时间的锁给筛选出来
, 进一步观察是否死锁, 因为有些长时间阻塞的锁`也可能是 饿锁
然后针对筛选出来的几个可能是死锁的进行深入分析
, 首先可以看到这些锁的类型是处于阻塞的,
然后鼠标右键
任意一个锁上面 选择在堆遍历器中显式所选内容:
然后在对堆遍历器
中点击图表, 就可以看到这个锁所在的代码位置
, 然后 看一看代码
就知道到底有没有死锁,还是饿锁了
通常来说产生死锁的原因主要有:
-
没有设置锁的失效时间
, 然后代码里可能因为异常没有处理, 锁没有在finaly代码块中释放导致其它线程无法获取锁而陷入等待 -
锁互相竞争(类似上图这种)
,线程1持有A锁尝试获取B锁, 线程2持有B锁尝试获取A锁, 谁也不让谁, 互相干等着。 这种情况要注意加锁的顺序
, 让线程1是先获得了A锁,再去获取B锁, 然后线程2去尝试获取A锁,再获取B锁, 按这样的顺序就不会产生死锁. -
由线程优先级产生的饿锁
,即高优先级线程一直占着资源不放而导致其他线程得不到执行, 饿锁不算死锁,但也要引起重视,否则同样会造成资源浪费, 可以通过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后
剩余已用内存
是否处于不断递增
之中,如果是 ,则极有可能发生了内存泄漏.
通过线上服务不可用
和 监控到的数据
, 几乎可以确认是发生了内存泄漏,下面开始排查,到底是哪里发生了内存泄漏?写了什么禽兽代码让内存泄漏了???
-
第一步:通过
Jprofiler连接到本地或者远程JVM
(考虑到安全问题,可以用远程dump的日志导入Jprofiler
) -
第二步:点击
实时内存菜单下的所有对象
, 然后点击标记当前对象, 然后持续观察实例计数列,相差列,大小列变化
可以从以下几个线索去缩小范围:
-
可能发生内存泄漏的一般有 char[],String,Map,List,Object[] 等数据,可以重点去看看
-
占据大量内存空间 或是 实例计数超大的
一般会导致内存泄漏且影响到服务正常吞吐的,
大小列的值都不会太小
,毕竟一个应用的最大堆至少也会指定/默认在256Mb以上
,像这种几百kb级别的
,即便在持续增长,想要让系统不可用
,也得积累很久很久 -
多次点击运行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.总结
-
如果没有Jprofiler这类工具, 在生产环境发生内存泄漏, 去一行一行review所有代码是不现实的, 通过此工具我们可以在较短的时间内定位到导致内存泄漏出现的代码位置, 然后review该位置的代码即可.
-
内存泄漏的难的主要是
定位
, 解决起来一般比较简单, 重启生产环境应用,让服务恢复正常, 然后在把导致内存泄漏的代码优化(该释放的释放,强引用显示置为为null...
),改好之后测试并重新发布即可解决.
5.后话
当这些问题出现在生产环境时,一般都会带来严重的损失,而且排查和分析起来难度非常大, 在养成良好编码习惯, 尽量去规避死锁,内存溢出,及内存泄漏, 防患于未然是最好的
。
- 多学点监控和解决方式, 或许有一天还真能派上用场.像这类
低频使用
的知识,最好能总结一遍,留下文档,
下次再碰到时,可以快速回忆,
相关文章:

【Jvm】性能调优(拓展)Jprofiler如何监控和解决死锁、内存泄露问题
文章目录 Jprofiler简介1.安装及IDEA集成Jprofiler2.如何监控并解决死锁3.如何监控及解决内存泄露(重点)4.总结5.后话 Jprofiler简介 Jprofilers是针对Java开发的性能分析工具(免费试用10天), 可以对Java程序的内存,CPU,线程,GC,锁等进行监控和分析, 1.安装及IDEA集成Jprofil…...

运行错误(竞赛遇到的问题)
在代码提交时会遇见这样的错误: 此处运行错误不同于编译错误和答案错误,运行错误是指是由于在代码运行时发生错误,运行错误可能是由于逻辑错误、数据问题、资源问题等原因引起的。这些错误可能导致程序在运行时出现异常、崩溃。 导致不会显示…...
nodename nor servname provided, or not known
异常信息 在 Maven 打包过程中出现的 nodename nor servname provided, or not known 异常通常是由于 Maven 无法解析某个域名,这可能是因为网络问题、DNS 解析失败或者 Maven 配置中指定的仓库地址错误导致的。这个问题通常出现在 Maven 试图从远程仓库下载依赖时 …...

前端vue金额用逗号分隔
实现效果 代码 template部分 <el-input v-model"state.val"></el-input><div>{{ priceFor(state.val) }}</div> js部分 const state reactive({ val: });const priceFor (val)> {if(!val){return }else if(val.length<4){return…...

vulvhub-----Hacker-KID靶机
打靶详细教程 1.网段探测2.端口服务扫描3.目录扫描4.收集信息burp suite抓包 5.dig命令6.XXE漏洞读取.bashrc文件 7.SSTI漏洞8.提权1.查看python是否具备这个能力2.使用python执行exp.py脚本,如果提权成功,靶机则会开放5600端口 1.网段探测 ┌──(root…...

遨博I20协作臂关节逆解组Matlab可视化
AUBO I20协作臂关节逆解组Matlab可视化 前言1、RTB使用注意点2、代码与效果2.1、完整代码2.2、运行效果 总结 前言 注意:请预先配置好Matlab和RTB机器人工具箱环境,本文使用matlab2022b和RTB10.04版本 工作需要,使用matlab实现对六轴机械臂…...

力扣题目训练(15)
2024年2月8日力扣题目训练 2024年2月8日力扣题目训练507. 完美数520. 检测大写字母521. 最长特殊序列 Ⅰ221. 最大正方形237. 删除链表中的节点115. 不同的子序列 2024年2月8日力扣题目训练 2024年2月8日第十五天编程训练,今天主要是进行一些题训练,包括…...

PCB差模辐射是如何产生的
在电路应用中,高频时钟信号往往会采用差分线传输模式,其优点是在提高速率的同时减小功耗和提高抗扰度,因此,差模辐射就成为电路正常工作的结果,是电流流过导体形成的环路所产生,差模辐射模型可以被模拟为一个小环形天线,对于一个面积为A的小环路,载有电流Idm,在远场中…...

车载诊断协议DoIP系列 —— 协议中术语解释和定义
车载诊断协议DoIP系列 —— 协议中术语解释和定义 我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师(Wechat:gongkenan2013)。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 本就是小人物,输了就是输了,不要在意别人怎么看自己。江湖一碗茶,…...
【退役之重学前端】关于在控制台得到undefined的事
在浏览器控制台中,undefined 会时不时地,在我不想看到的地方出现。如果你遇到相同的问题,在这篇博客中你会得到答案。 先来看代码块 function test(){} test()//undefined再看下一个代码块 function test(){return 1; } test()//1再来看一个…...
指数和估计六大问题
1955年英国著名数学家R.A.Rankin在牛津大学出版的数学刊物Quart.J.Math.发表了论文(现 FRS D.R.Heath-Brown为主编),专门讲van der Corput方法产生的指数对理论(1933年E.Phillips提出的精彩理论,好友曲阜师范大学毕业中…...
【软件相关】基于Alist挂载云盘到本地文件资源管理器
文章目录 0 前言1 Alist挂载云盘2 RaiDrive配置3 rclone配置 0 前言 因为最近在研究各种云盘存储影视资源的方法,无意间看到一个教程是利用软件将云盘挂载到本地的资源管理器,这样就能实现类似本地文件操作的方式来操作云盘文件,还是有点意思…...
Java多线程系列——锁
0.引言 在并发编程中,锁是一种重要的同步机制,用于控制对共享资源的访问。Java 提供了多种锁的实现,每种锁都有不同的特性和适用场景。本文将深入介绍 Java 中常见的锁类型,包括内置锁、显式锁、读写锁等,并讨论它们的…...

蓝牙BLE学习-GAP
1.概述 GAP层(Generic access profile-通用访问配置文件)。GAP是对LL层payload(有效数据包)如何进行解析的两种方式的一种,而且也是最简单的一种。GAP简单的对LL payload进行一些规范和定义,因此GAP能实现的…...
算法训练营day28(补), 贪心算法2
//122. 买卖股票的最佳时机 II func maxProfit(prices []int) int { result : 0 //利润总和 for i : 1; i < len(prices); i { if prices[i]-prices[i-1] > 0 { result result (prices[i] - prices[i-1]) } } return result } //55. 跳跃游戏 func canJump(nums []…...

Vue核心基础4:绑定样式、条件渲染、列表渲染
1 绑定样式 【代码】 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>绑定样式</title><s…...
go-zero读取mysql部分字段
读取部分字段,使用函数 QueryRowPartialCtx 。 假设有如下一张表: CREATE TABLE test (id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, ctime DATETIME);要读取字段 ctime 值。 定义一结构体: type X struct {state int db:"…...

反转一个单链表
反转一个单链表 题意:反转一个单链表。 示例: 输入: 1->2->3->4->5->NULL 输出: 5->4->3->2->1->NULL 思路 需要虚拟节点么? 答:不需要,因为没有删除节点,只是改变了节点的指向。 遍…...

拿捏c语言指针(中)
前言 书接上回 拿捏c语言指针(上) 此篇主要讲解的是指针与数组之间的爱恨情仇,跟着我的脚步一起来看看吧~ 创造不易,可以帮忙点点赞吗 如有差错,欢迎指出 理解数组名 数组名是首元素地址 例外 1.sizeof࿰…...

鸿蒙语言ArkTS(更好的生产力与性能)
ArkTS是鸿蒙生态的应用开发语言 ArkTS提供了声明式UI范式、状态管理支持等相应的能力,让开发者可以以更简洁、更自然的方式开发应用。 同时,它在保持TypeScript(简称TS)基本语法风格的基础上,进一步通过规范强化静态检…...

【Axure高保真原型】引导弹窗
今天和大家中分享引导弹窗的原型模板,载入页面后,会显示引导弹窗,适用于引导用户使用页面,点击完成后,会显示下一个引导弹窗,直至最后一个引导弹窗完成后进入首页。具体效果可以点击下方视频观看或打开下方…...

stm32G473的flash模式是单bank还是双bank?
今天突然有人stm32G473的flash模式是单bank还是双bank?由于时间太久,我真忘记了。搜搜发现,还真有人和我一样。见下面的链接:https://shequ.stmicroelectronics.cn/forum.php?modviewthread&tid644563 根据STM32G4系列参考手…...

调用支付宝接口响应40004 SYSTEM_ERROR问题排查
在对接支付宝API的时候,遇到了一些问题,记录一下排查过程。 Body:{"datadigital_fincloud_generalsaas_face_certify_initialize_response":{"msg":"Business Failed","code":"40004","sub_msg…...
DeepSeek 赋能智慧能源:微电网优化调度的智能革新路径
目录 一、智慧能源微电网优化调度概述1.1 智慧能源微电网概念1.2 优化调度的重要性1.3 目前面临的挑战 二、DeepSeek 技术探秘2.1 DeepSeek 技术原理2.2 DeepSeek 独特优势2.3 DeepSeek 在 AI 领域地位 三、DeepSeek 在微电网优化调度中的应用剖析3.1 数据处理与分析3.2 预测与…...
React Native 导航系统实战(React Navigation)
导航系统实战(React Navigation) React Navigation 是 React Native 应用中最常用的导航库之一,它提供了多种导航模式,如堆栈导航(Stack Navigator)、标签导航(Tab Navigator)和抽屉…...
逻辑回归:给不确定性划界的分类大师
想象你是一名医生。面对患者的检查报告(肿瘤大小、血液指标),你需要做出一个**决定性判断**:恶性还是良性?这种“非黑即白”的抉择,正是**逻辑回归(Logistic Regression)** 的战场&a…...
【Linux】C语言执行shell指令
在C语言中执行Shell指令 在C语言中,有几种方法可以执行Shell指令: 1. 使用system()函数 这是最简单的方法,包含在stdlib.h头文件中: #include <stdlib.h>int main() {system("ls -l"); // 执行ls -l命令retu…...
在rocky linux 9.5上在线安装 docker
前面是指南,后面是日志 sudo dnf config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo sudo dnf install docker-ce docker-ce-cli containerd.io -y docker version sudo systemctl start docker sudo systemctl status docker …...

【开发技术】.Net使用FFmpeg视频特定帧上绘制内容
目录 一、目的 二、解决方案 2.1 什么是FFmpeg 2.2 FFmpeg主要功能 2.3 使用Xabe.FFmpeg调用FFmpeg功能 2.4 使用 FFmpeg 的 drawbox 滤镜来绘制 ROI 三、总结 一、目的 当前市场上有很多目标检测智能识别的相关算法,当前调用一个医疗行业的AI识别算法后返回…...
Element Plus 表单(el-form)中关于正整数输入的校验规则
目录 1 单个正整数输入1.1 模板1.2 校验规则 2 两个正整数输入(联动)2.1 模板2.2 校验规则2.3 CSS 1 单个正整数输入 1.1 模板 <el-formref"formRef":model"formData":rules"formRules"label-width"150px"…...