首页 推广正文

JVM垃圾回收与一次线上内存泄露问题分析和解决过程

admin 推广 2022-10-20 15:14:11 461 0

前言

内存泄漏(Memory Leak)是指程序中己动态分配的堆内存由于某种原因程序未释放或无法释放,造成系统内存的浪费,导致程序运行速度减慢甚至系统崩溃等严重后果。

Java是由C++发展来的,抛弃了C++中一些繁琐容易出错的东西,程序员忘记或者错误的内存回收会导致程序或系统的不稳定甚至崩溃,而Java的GC(Garbage Collection)是自动检测不用的对象,达到自动回收,

既然是自动检测回收不用对象,那Java有没有可能出现内存泄露的情况呢?

一、JVM判断垃圾对象方法

Java又是如何知道哪些对象不再使用,需要回收的呢?实际上JVM中对堆内存进行回收时有一套可达性分析算法,该算法的思路就是通过被称为引用链(GC Roots)的对象作为起点,搜索所走过的路径称为引用链(Reference Chain),当一个对象到GC Roots没有任何引用链相连时,则证明此对象是不可用的,最终不可用的对象会被回收。

GC Roots对象可归纳为如下几种:

虚拟机栈(栈帧中的本地变量表)中引用的对象;方法区中类静态属性引用的对象;方法区中常量引用的对象;本地方法栈中JNI(即一般说的Native方法)引用的对象;

了解了基本JVM如何判断垃圾对象原则后有助于理解java如何发生内存泄露,由于篇幅有限这里就不对jvm内存空间划分和垃圾回收算法详细的叙述了。

二、 根据现象分析并定位问题

先说说事情的现象吧,本来运行好好的活动项目某一天突然服务报警(当时没有任何上线),客服陆续收到几个用户反馈投诉,查看日志发现有一台服务器各种报超时异常、cpu负载高,服务重启后一切正常,再过一天又是超时异常、cpu负载高。

乍一看现象还有点摸不着头脑,但有前面的内容聪明的你肯定猜到了什么原因,如果没有上述铺垫,我们根据该现象定位问题呢?

我们一般发现问题,都是从现象到本质,逐步递进的,如何从现象中提取有用信息加工并做判断很重要。

异常特征分析

特征一、报错范围:看到的是大量业务日志异常,大量操作超时和执行慢,redis超时、数据库执行超时、调用http接口超时

分析:首先排除是某一个db的问题

网络问题,ping服务器是通的,无丢包,查看wonder*控后台网络无丢包、网卡无故障 --排除网络问题

服务器cpu问题,top命令发现java应用cpu异常高,查看wonder*控后台也发现cpu负载高–这里并不是根本原因,只是现象

特征二、报错普遍性:查看其它服务器是否有相同异常,相同的代码,相同的jvm配置,只有一台服务器有问题,其它服务器正常

分析:跟这一台服务器代码或者系统设置有关系

操作系统设置导致 --这台服务器是虚拟机,跟其他虚拟机比较,参数配置一样,排除操作系统设置(当时上来先入为主,就认为是虚拟机配置不一样导致cpu过高,走了弯路)

负载均衡流量不均导致 --查看wonder*控后台流量无明显高,可以排除该原因

该机器运行与其它机器不一样的业务 --当时认为代码都一样的,忽略了定时任务

特征三、持续性:查看日志,开始报错后持续不断报错,cpu使用率持续高

分析:不是偶发状况

查看数据指标

ps: 这里简单说一下我们的业务*控后台,对诊断问题起很大的作用,可以看到cpu、线程、jvm内存等曲线图

使用的是springboot actuator报点 + prometheus收集 + grafana图形展示

springboot 只需要加上这两个包,加上一个配置就行了,零侵入,prometheus定时每10秒一次请求http接口收集数据,也不会对业务产生影响

基于springboot的业务报点gradle配置:compileorg.springframework.boot:spring-boot-starter-actuatorcompileio.micrometer:micrometer-registry-prometheus复制

yml配置文件加上:

management:endpoints:web:exposure:include: health,prometheus 默认报点的url:http://ip:port/actuator/prometheus安装prometheus并配置对应的ip和收集的url安装grafana,并去grafana官网 dashboards中下载一个叫Spring Boot 2.1 Statistics的模板,导入就能看到漂亮的统计界面了

grafana*控后台

内存泄露-年轻代的eden区的特征:

内存泄露-老年代的特征:

内存泄露-年轻代的survivor区的特征:

内存泄露-gc Stop The World 曲线图:

有这个图基本就可以断定为内存泄露,

3.如何定位问题代码

1、查询pid

ps -ef|grep projectName 2、dump当前jvm堆内存(注意:要先切换到启动java应用的用户,并且切走流量,因为dump内存会卡住进程)

jmap -dump:live,format=b,file=dump.hprof

3、下载内存分析工具mat (Memory Analyzer Tool)(https://www.eclipse.org/mat/downloads.php),并分析,由于dump下来的内存比较大,建议选择linux版本,直接在linux上分析

//解压

unzip-oMemoryAnalyzer-1.9.1.20190826-linux.gtk.x86_64.zipcdmat

//执行分析命令

<code>./ParseHeapDump.sh<dump文件>org.eclipse.mat.api:suspects org.eclipse.mat.api:overview org.eclipse.mat.api:top_components

健康食品 产品推荐 洗护测评 知识科普

版权声明 1、本网站名称:三九知识
2、本站永久网址:www.1puu.com
3、本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任
4、如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 aaw4008@foxmail.com 网站右下角【投诉删除】可进入实时客服
5、本站一律禁止以任何方式发布或转载任何违法的相关信息,访客发现请向站长举报
本文链接:http://1puu.com/post/1170.html