【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)基本语法风格的基础上,进一步通过规范强化静态检…...

VBA技术资料MF120:打印固定标题行列
我给VBA的定义:VBA是个人小型自动化处理的有效工具。利用好了,可以大大提高自己的工作效率,而且可以提高数据的准确度。“VBA语言専攻”提供的教程一共九套,分为初级、中级、高级三大部分,教程是对VBA的系统讲解&#…...

MongoDB聚合运算符:$add
$add运算符将将数字相加或将数字和日期相加。如果参数之一是日期,则 $add会将其他参数视为毫秒,并添加到日期中。 语法 { $add: [ <expression1>, <expression2>, ... ] }参数可以是任何有效的表达式,只要能否解析为数值或日期…...

《剑指Offer》笔记题解思路技巧优化 Java版本——新版leetcode_Part_4
《剑指Offer》笔记&题解&思路&技巧&优化_Part_4 😍😍😍 相知🙌🙌🙌 相识😢😢😢 开始刷题1. LCR 148. 验证图书取出顺序——栈的压入、弹出序列2. LCR 14…...

数据库第四次实验
目录 1.建立数据表并插入数据 2 视图的创建 2.1 行列子集视图的创建 2.2 多表视图 2.3视图上建立视图 2.4分组视图 2.5带表达式的视图 3 删除视图 4 查询视图 5 更新视图 5.1 修改某一个属性 5.2 删除一条数据 5.3 插入…...

基于PPNSA+扰动算子的车间调度最优化matlab仿真,可以任意调整工件数和机器数,输出甘特图
目录 1.程序功能描述 2.测试软件版本以及运行结果展示 3.核心程序 4.本算法原理 5.完整程序 1.程序功能描述 基于PPNSA扰动算子的车间调度最优化matlab仿真,可以任意调整工件数和机器数,输出甘特图和优化收敛曲线。 2.测试软件版本以及运行结果展示 MATLAB2022a版本运行…...

UnityShader——06UnityShader介绍
UnityShader介绍 UnityShader的基础ShaderLab UnityShader属性块介绍 Properties {//和public变量一样会显示在Unity的inspector面板上//_MainTex为变量名,在属性里的变量一般会加下划线,来区分参数变量和临时变量//Texture为变量命名//2D为类型&…...

人工智能学习与实训笔记(一):零基础理解神经网络
人工智能专栏文章汇总:人工智能学习专栏文章汇总-CSDN博客 本篇目录 一、什么是神经网络模型 二、机器学习的类型 2.1 监督学习 2.2 无监督学习 2.3 半监督学习 2.4 强化学习 三、网络模型结构基础 3.1 单层网络 编辑 3.2 多层网络 3.3 非线性多层网络…...

LeetCode刷题小记 一、【数组】
LeetCode刷题小记 一、【数组】 文章目录 LeetCode刷题小记 一、【数组】写在前面1. 数组1.1 理论基础1.2 二分查找1.3 移除元素1.4 有序数组的平方1.5 长度最小的子数组1.6 螺旋矩阵II Reference 写在前面 本系列笔记主要作为笔者刷题的题解,所用的语言为Python3&…...

iOS总体框架介绍和详尽说明
iOS是由苹果公司开发的移动操作系统,为iPhone、iPad、iPod Touch等设备提供支持。iOS采用了基于Unix的核心(称为Darwin),并采用了类似于Mac OS X的图形用户界面。以下是iOS的总体框架介绍和详尽说明: UIKit框架&#…...

【C++】const与constexpr详解
1. constexpr:常量表达式 所谓常量表达式,指的就是由多个(≥1)常量组成的表达式。换句话说,如果表达式中的成员都是常量,那么该表达式就是一个常量表达式。这也意味着,常量表达式一旦确定,其值将无法修改。 实际开发中,我们经常会…...