利用JProfiler对应用服务器内存泄漏问题诊断一例(转)

利用JProfiler解析heapdump文件快速诊断JVM内存泄漏 本文详细介绍了如何利用JProfiler工具分析heapdump文件,快速诊断和定位JVM内存泄漏问题。文章从线上OOM告警入手,讲解了如何获取heapdump证据、使用JProfiler核心界面解析内存快照、追踪对象引用链,并针对Spring Boot应用提供了常见泄漏点分析与实战技巧,帮助开发者高效解决内存顽疾。 阅读详情

关键字: java

       在中间件应用服务器的整体调优中,有关于等待队列、执行线程,EJB池以及数据库连接池和Statement Cache方面的调优,这些都属于系统参数方面的调优,本文主要从另外一个角度,也就是从应用的角度来解决中间件应用服务器的内存泄露问题,从这个角度来 提高系统的稳定性和性能。

项目背景

问题描述

某个大型项目(Use Case用例超过300个),在项目上线后,其Web应用服务器经常宕机。表现为:

1. 应用服务器内存长期不合理占用,内存经常处于高位占用,很难回收到低位;

2. 应用服务器极为不稳定,几乎每两天重新启动一次,有时甚至每天重新启动一次;

3. 应用服务器经常做Full GC(Garbage Collection),而且时间很长,大约需要30-40秒,应用服务器在做Full GC的时候是不响应客户的交易请求的,非常影响系统性能。

Web应用服务器的物理部署

      一台Unix服务器(4CPU,8G Memory)来部署本Web应用程序;Web应用程序部署在中间件应用服务器上;部署了一个节点(Node),只配置一个应用服务器实例(Instance),没有做Cluster部署。

Web应用服务器启动脚本中的内存参数

MEM_ARGS="-XX:MaxPermSize=128m -XX:MaxNewSize=512m -Xms3096m
-Xmx3096m -XX:+Printetails -Xloggc:./inwebapp1/gc.$$"

可以看出目前生产系统中Web应用服务器的内存分配为3G Memory。

Web应用服务器的重要部署参数

参数名称 参数值 参数解释
kernel.default(Thread Count) 120 执行线程数目,是并发处理能力的重要参数
Session Timeout 240分钟(4小时) HttpSession会话超时

 

分析

分析方法

内存长期占用并导致系统不稳定一般有两种可能:

1. 对象被大量创建而且被缓存,在旧的对象释放前又有大量新的对象被创建使得内存长期高位占用。

  • 表 现为:内存不断被消耗、在高位时也很难回归到低位,有大量的对象在不断的创建,经过很长时间后又被回收。例如:在HttpSession中保存了大量的分 页查询数据,而HttpSession的会话超时时间设置过长(例如:1天),那么在旧的对象释放前又有大量新的对象在第二天产生。
  • 解决办法:对共享的对象可以采用池机制进行缓存,避免各自创建;缓存的临时对象应该及时释放;另一种办法是扩大系统的内存容量。

2. 另一种情况就是内存泄漏问题

  • 表现为:内存回收低位点不断升高(以每次内存回收的最低点连成一条直线,那么它是一条上升线);内存回收的频率也越来越高,内存占用也越来越高,最终出现"Out of Memory Exception"的系统异常。
  • 解决办法:定位那些有内存泄漏的类或对象并修改完善这些类以避免内存泄漏。方法是:经过一段时间的测试、监控,如果某个类的对象数目屡创新高,即使在JVM Full GC后仍然数目降不下来,这些对象基本上是属于内存泄漏的对象了。

问题定位

这里请看5月份 Web应用服务器的内存回收图形:

《注意:5月18日早上10点重新启动了Web服务器,5月20日早上又重新启动了Web服务器。》

  • 在Web应用重要部署参数中,我们知道:Session的超时时间为4个小时,我们在监控平台也观测到:在18日晚上10点左右所有的会话都过期了,从图形一中也能看出18日晚上确实系统的内存有回收到40%(就象股票的高位跳水);
  • 从图形一(5月18日)中我们也能看到Full GC回收后的内存占用率走势(红色曲线),上午基本平滑上升到20%(内存占用率),中午开始上升到30%,下午上升到40%
  • 从图形二(5月19日)中我们也能看到Full GC回收后的内存占用率走势(红色曲线),上午又上升到了60%,到下午上升到了70%。
  • 从黄色曲线(GC花费的时间,以秒为单位),Full GC的频率也在增快,时间耗费也越来越长,在图形一中基本高位在20秒左右,到19日基本都是30-40秒之间了。

 图形一 5月18日
图形一 5月18日

图二
图二

通过上述分析,我们基本定位到了Web应用服务器的内存在高位长期占用的原因了:是内存泄露!并且正是由于这个原因导致系统不稳定、响应客户请求越来越慢的。

解决方法

方法如下:

  • 我们从图形二中发现,在8.95(将近9点钟)到9.66(将近9点40)期间有几次Full GC,但是有内存泄漏,从占用率40%上升到50%左右,泄漏了大约10%的内存,约300M;
  • 我们在自己搭建的Web应用服务器平台(应用软件版本和生产版本一致)做这一阶段相同的查询交易;表明对同一个黑盒(Web应用)施加同样的刺激(相同的操作过程和查询交易)以期重现现象;
  • 我们使用Jprofiler工具对Web应用服务器的内存进行实时监控;
  • 做完这些交易后,用户退出系统,并等待Web应用服务器的HttpSession超时(我们这里设置为15分钟);
  • 我们对Web应用服务器做了两次强制性的内存回收操作。

发现如下:


图三
图三

如图三所示,内存经过HttpSession超时后,并强制gc后,仍然有大量的对象没有释放。例如:gov.gdlt.taxcore.comm.security.MenuNode,仍然有807个实例没有释放。

我 们继续追溯发现,这些MenuNode首先存放在一个ArrayList对象中,然后发现这个ArrayList对象又是存放在 WHsessionAttrVO对象的Map中,WHsessionAttrVO 对象又是存放在ExternalSessionManager的staic Map中(名称为sessionMap),如图四所示。


图四
图四

我 们发现gov.gdlt.taxcore.taxevent.xtgl.comm.WHsessionAttrVO中保存了EJBSessionId信息 (登录用户的唯一标志,由用户id+登录时间戳组成,每天都不同)和一个HashMap,这个HashMap中的内容有:

  • ArrayList: 内有MenuTreeNodes(菜单树节点)
  • HashMap: 内有操作人员代码信息
  • CurrentVersion:当前版本号
  • CurrentTime:当前系统时间

WHsessionAttrVO 这个对象的最终存放在ExternalSessionManager的static Map sessionMap中,由于ExternalSessionManager是一个全局的单实例,不会释放,所以它的成员变量sessionMap中的数 据也不会释放,而Map中的Key值为EJBSessionId,每天登录的用户EJBSessionId都不同,就造成了每天的登录信息(包括菜单信 息)都保存在sessionMap中不会被释放,最终造成了内存的泄漏。


图五
图五

如上图所示:WHsessionAttrsVO对象中除了有一个String对象(内容是EJBSessionId),还有一个HashMap对象。


图六
图六

如上图所示,这个HashMap中的内容主要有menuTreeNodes为key,value为ArrayList的对象和以czrydminfo为key,value为HashMap对象的数据。


图七
图七

如上图所示:menuTreeNodes为key,value为ArrayList对象中包含的对象有许多的MenuNode对象,封装的都是用户的菜单节点。


图八
图八

如上图所示,最顶层(Root)的初始对象为一个ExternalSessionManager对象,其中的一个成员变量为static (静态的),名称为:sessionMap,这个对象是singleton方式的,全局只有一个。

初步估量

我们从图形一和图形二中可以看出,每天应用服务器损失大约40%的内存,大约1G左右。

从 图形四可以看出,当前用户(Id=24400001129)有807个菜单项(每个菜单项为一个MenuNode 对象实例,图形四中的这个实例的size为592 Byte),这些菜单数据和用户基本登录信息(czrydmInfo HashMap)也都存放在WHsessionAttrVO对象中,当前这个WHsessionAttrVO对象的size为457K。

我们做如下估算:

假 设平均每天有4千人(估计值,这个数值仅仅是5月19日峰值的1/2左右)登录系统(有重复登录的现象,例如:上午登录一次,中午退出系统,下午登录一 次),以平均每人占用200K(估计值,是用户id=24400001129 的Size的1/2左右)来计算,一天泄漏的内存约800M,比较符合目前内存泄漏的情况。当然,这种估计仍然需要经过实践的检验,方法是:当这次发现的 内存泄漏问题解决后看系统是否还有其它内存泄漏问题。

 

方案

ExternalSessionManager类是当初某某软件商设计的用来解决Web服务器负载均衡的模块,这个类主要用来保存客户的基本登录信息(包括会话的EJBSessionId),以维护多个Web服务器之间的会话信息一致。

改进方案有两种:

  • 从架构设计方面改进

    实现Web层的负载均衡有很多标准的实现方式。例如:采用负载均衡设备(硬件或软件)来实现。

    如果采用新的Web层的负载均衡方式,那么就可以去掉ExternalSessionManager这个类了。

  • 从应用实现方面改进

    保留当前的Web层的负载均衡设计机制,仅仅从应用实现方面解决内存泄漏问题,首先菜单信息不应该保存在ExternalSessionManager中。其次,增加对ExternalSessionManager类中用户会话登录信息的清除,有几种方式可以选择:

    • 被动方式,当HttpSession会话超时(或过期)被Web应用服务器回收时清除相应的ExternalSessionManager中的过期会话登录信息。
    • 主动方式,可以采用任务定时清理每天的过期会话登录信息或线程轮询清理。
    • 采 用新的会话登录信息存储方式,ExternalSessionManager的sessionMap中的key值不再以EJBSessionId作为键 值,而是以用户id(EJBSessionId的前11位)代替。由于用户id每天都是一样的,所以不会造成内存泄漏。保存得登录信息也不再包含菜单节点 信息,而只是登录基本信息。最多也只是保存整个系统所有的用户id及其基本登录信息(大约每个用户的登录信息只有1.5K左右,而目前这个系统的营业网点 用户为1万左右,所以大约只占用Web服务器15M内存)。

 

实施情况

采用的方案:某某软件商采用了新的会话登录信息存贮方案,即:ExternalSessionManager的成员变量sessionMap中不再保存用户菜单信息,只保存基本的登录信息;存储方式采用用户id(11位)作为键值(key)来保留用户基本登录信息。

基 本分析:由于基本登录信息只有1K左右,而目前内网登录的用户总数也只有8887个,所以只保存了大约10M-15M的信息在内存,占用量很小,并且不会 有内存泄漏。用户菜单信息保存在session中,如果用户退出时点击logout页面,那么应用服务器可以很快地释放这部分内存;如果用户直接关闭窗 口,那么保存在session中的菜单信息只有等会话超时后才会由系统清除并回收内存。

监控状况:


图九
图九

如 图九所示,ExternalSessionManager中只保留了简单的登录信息(Map中保存了WHsessionAttrVO对象),包括:当前版 本(currentversion),操作人员代码基本信息(czrydmInfo),当前时间(currenttime)。


图十
图十

如图十所示,这个登录用户的基本信息只有1368 bytes,大约1.3K


图十一
图十一

如图十一所示,一共有两个用户(相同的用户id)登录系统,当一个用户使用logout页面退出时,保留在session中的菜单信息(MenuNode)立刻释放了,所以Difference一栏减少了806个菜单项。


图十二
图十二

如 图十二所示,当另外一个会话超时后,应用服务器回收了整个会话的菜单信息(MenuNode),图上已经没有MenuNode对象了。并且由于是同一个用 户登录,所以保留在ExternalSessionManager成员变量sessionMap中的对象WHsessionAttrVO只有一个 (id=24400001129),而没有产生多个,没有因为多次登录而产生多个对象的后果,避免了内存泄漏问题的出现,解决了前期定位的内存泄漏问题。


图十三
图十三

如图十三所示,经过gc内存回收后,发现内存回收比较稳定,基本都回收到了最低点,也证明了内存没有泄露。

结论与建议:从测试情况看,解决了前期定位的内存泄漏问题。

生产系统实施后的监控与分析

经过调优后,我们发现:在2005年6月2日晚9点40左右重新部署、启动了Web应用服务器(采用了新的调优方案)。经过几天的监控运行,发现Web应用服务器目前运行基本稳定,目前没有出现新的内存泄漏问题,下列图示说明了这一点


图十四 2005年6月2日
图十四 2005年6月2日

如图十四所示,6月2日晚21.7(21点42分)重新启动应用服务器,内存占用很少,大约为15%(请看红色曲线),每次GC消耗的时间也很短,大约在5秒以内(请看黄色曲线)。


图十五 2005年6月3日周五
图十五 2005年6月3日周五

如 图十五所示,在6月3日周五的整个工作日内,内存的回收基本到位,回收位置控制在20%-30%之间,也就是在600M-900M之间(请看红色曲线的最 低点),始终可以回收2G的内存供应用程序使用,每次GC的时间最高不超过20秒,Full GC平均在10秒左右,时间消耗比较短(请看黄色曲线)。


图十六2005年6月5日周日
图十六2005年6月5日周日

如图十六所示,在周日休息日期间,Web应用服务器全天只做了大约4次Full GC(黄色曲线中的小山峰),时间都在10秒以内;大的Full GC后,内存只占用10%,内存回收很彻底。


图十七 2005年6月6日周一
图十七 2005年6月6日周一

如图十七所示,在周一工作日期间,内存回收还是不错的,基本可以回收到30%(见红色曲线的最低点),即:占用900M内存空间,剩余2G的内存空间;Full GC的时间大部分控制在20秒以内,平均15秒(见黄色曲线)。


图十八 2005年6月7日周二
图十八 2005年6月7日周二

如图十八所示,在6月7日周二早上,大约8:30左右,Web应用服务器作了一次Full GC,用了10秒的时间,把内存回收到了10%的位置,为后续的使用腾出了90%的内存空间。内存回收仍然比较彻底,说明基本没有内存泄漏问题。

经过这几天的监控分析,我们可以看出:

  • Web应用服务器的内存使用已经比较合理,内存在工作日的占用在20%至30%之间,约1G的内存占用,有2G的内存空间富裕;而在空闲时间(周日,每天的凌晨等)内存可以回收到10%,有90%的内存空间富裕;
  • Web应用服务器的Full GC的次数明显减少了并且每次Full GC占用的时间也很少,基本控制在10-20秒之间,有的甚至在10秒以内,明显改善了内网应用服务器内存的使用;
  • 从6月2日重新部署之后,Web应用服务器没有出现宕机重启的现象。

 

总结

 通过本文,我们可以看到,内存的泄露将会导致服务器的宕机,系统性能就更别说了。对于系统内存泄露问题应该从服务器GC日志方面进行早诊断,使用工具早确认并提出解决方案,排除内存泄露问题,提高系统性能,以规避项目风险。

原作者:曾胜财 , IBM BCS 部门 I/T架构师

顺藤摸瓜找泄漏:Java内存泄漏的快照取证、支配树归因与代码根治解析 Java内存泄漏的本质是“活着的废物”:对象已无用却仍经引用链可达。本文给出止血留证、确认泄漏、取堆快照、归因定位、根治修复、验证回归的六步闭环,讲清GC后水位、三次直方图、OOM分诊、自动与手动取证的代价,以及Shallow/Retained、支配树、累积点与最短引用链的原理;并用自研迷你HPROF分析器复现MAT核心算法,在埋有四处泄漏的订单服务上实测定位与修复效果,纠正“不可达对象即泄漏”“循环引用致泄漏”等误区,总结常见泄漏模式的正确写法、单测探针与线上监控,并注明适用的版本和范围。 阅读详情

相关推荐

应用服务器内存泄漏诊断与解决:使用JProfiler

本文还有配套的精品资源,点击获取 简介:内存泄漏是导致应用服务器性能下降的主要问题之一,尤其是长时间运行的服务中更为常见。JProfiler作为一款强大的Java性能分析工具,在诊断内存泄漏方面特别有效。本文将详细介绍如何利用JProfiler来识别并解决应用服务器中的内存泄漏问题。这包括如何配置连接、进行内存快照、分析内存泄漏迹象、定位问题代码以及最终解决内存泄漏的步骤。JProfiler的内存分析、CPU剖析和线程监控功能对于检测内存泄漏和性能瓶颈非常有帮助。同时,文章也会强调使用JProf

weixin_33375360的博客 764

任务管理器两个java进程_java监视和管理控制台(jconsole)显示项目进程的内存为什么和windows任务管理器不一样?...

自己在网上找到了想要的答案:jvm不会把已经申请的内存还给OS, 因为很可能马上又要分配给新的对象,每次向 OS 申请内存是很慢的。所以管理控制台显示的内存使用情况和windows任务管理器中的不一样。jvm中有两个参数 MaxHeapFreeRatio, MinHeapFreeRatio 可以收缩堆,还内存给OS, 但只在client 模式下有效,而且是分次返还,0% on the first ...

weixin_34204530的博客 437

jprofiler9.2.1全部

jprofiler9.2.1全部,网上很多资料不全,下载了几个都不能用!这个我是我测试过的。

jprofiler java应用内存监控、诊断分析

很有可能造成内存溢出,方法名找到后去看源代码,告诉开发哪里写的不合理,如果不懂代码也可以了,最起码找到哪个方法有问题了,如果怀疑哪个方法有问题,就把这个方法放到Class Tracker里进行单独观察,发现full gc也没有变化,单独把这个方法放到了内存快照。参照上面的实例数或百分比都可以看出来一直在增加,实例数是950000,上面的是690000,Difference也是111%,大于上面的53%,强制进行full gc,即点击。右键cn.test.TestBean,选择第一个。...

学亮编程手记 921

JProfiler对应用服务器内存泄漏问题诊断

JProfiler对应用服务器内存泄漏问题诊断

阿里云导出的镜像raw转换成vmdk格式工具

阿里云导出的镜像raw转换成vmdk格式工具 1.安装java环境,安装教程不介绍了 2.raw2vmdk软件下载: 在我的链接里面: 3.使用 打开cmd.bat软件: java -jar raw2vmdk.jar (原镜像)C:\\images\\raw\\disk.img (转换的镜像)D:\\images\\vmdk\\disk.vmdk 4.vmware打开vmdk文件 ...

3843

Jprofile(二) - 查找内存泄露

Jprofile(二) - 查找内存泄露 3. 随后点击Live Memory -> All Object -> MarkCurrent 保存当前对象以及内存使用状态,状态条由红色转变为绿色

闸北米 1857

关于kafka面试问题整理

1.kafuka介绍 kafka是一个分布式流媒体平台,类似于消息队列和企业消息传递系统,Kafka对于zookeeper是强依赖,保存kafka相关的节点数据,所以安装Kafka之前必须先安装zookeeper 2.kafuka的使用流程 producer:发布消息的对象称之为生产者(producer) broker:一个独立的Kafka服务器,被称之为broker,多个broker可以组成kafka集群 topic:Kafka将消息保存到主题(topic)中,可以简单理解为Topic为文件

qq_42190033的博客 437

利用JProfiler对应用服务器内存泄漏问题诊断一例

在中间件应用服务器的整体调优中,有关于等待队列、执行线程,EJB池以及数据库连接池和Statement Cache方面的调优,这些都属于系统参数方面的调优,本文主要从另外一个角度,也就是从应用的角度来解决中间件应用服务器的内存泄露问题,从这个角度来提高系统的稳定性和性能。 项目背景 问题描述 某个大型项目(Use Case用例超过300个),在项目上线后,其Web应用服务器经常宕

xinye98的专栏 1268

wpf入门第五篇 WPF with ECharts

前言 本文是wpf入门系列第五篇,面向有winform或者web前端基础的、并且也有C#基础的同学。 ECharts是百度团队开发的开源免费的js图表控件库,非常强大,文档齐全。WPF中使用图表,除了可以选择devexpress或者oxyplot之类的专为wpf开发的图表控件之外,还可以考虑使用 WebBrowser+ECharts 来完成复杂的图表展示,其展示效果不亚于前者。 本文介绍了 WP...

wf824284257的博客 1万+

STM32 RTC_WaitForSynchro()死循环问题分析与LSI时钟优化实践

本文深入分析了STM32使用LSI时钟源时,调用RTC_WaitForSynchro()函数陷入死循环的根本原因。问题核心在于RTC时钟域未正确使能,导致硬件同步标志RSF无法置位。文章提供了通过显式调用RCC_RTCCLKCmd(ENABLE)函数启用RTC时钟总开关的解决方案,并分享了编写健壮RTC/BKP初始化代码、增加超时机制等最佳实践,确保系统稳定运行。

weixin_29185493的博客 510

【JVM 监控工具】性能诊断--JProfiler的使用

在 Java 的世界里,有许多诊断工具可供选择,既包括像 jmap、jstat 这样的简单命令行工具,又包括 JVisualvm、JProfiler 等图形化综合诊断工具,同时还有 SkyWalking、ARMS 这样的针对分布式应用的性能监控系统。下面分别对其进行介绍。

DreamSun的博客 1万+

网络系统实现技术之IPX与SPX

IPX/SPXNovell NetWare网络Novell公司为适应网络发展,将主机网络转换为PC网络,开发了Novell NetWare网络系统。该系统中基于客户机/服务器模式。以普通PC机做为客户机,以性能强大的服务器做为服务器,为客户机提供文件服务、数据库服务及其他服务。与前面的SNA模型一样,Novell NetWare也早于OSI模型,所以不能与OSI模型严格对应,但也有很明

成片的大树 9164

实战复盘:如何用JProfiler在30分钟内解决内存泄漏?

通过JProfiler分析Dump文件,开发者可以快速定位内存泄漏或大对象问题。生成准确的快照:确保JVM参数配置正确。掌握分析工具的核心功能:如引用链追踪、大对象筛选。结合代码与业务场景:避免“治标不治本”的临时修复。

南宫乘风-Linux运维-虚拟化容器-Python编程 ownit.top 2936

USB之ch376s数据手册

         最近师兄交给我一个项目,虽说刚学嵌入式起步,但上手一个项目怎说都是最好的快速学习方式。因为刚了解ch376s管理U盘的数据,所以先是看了ch376s的数据手册。那我就把数据手册直接放上来吧。。。。      1、概述 CH376 是文件管理控制芯片,用于单片机系统读写 U 盘或者 SD 卡中的文件。 CH376 支持 USB 设备方式和 USB 主机方式,并且内置了 USB 通...

iBGG的博客 6004

OpenOCD入门到精通:第 1 章 OpenOCD 概述

OpenOCD是一款开源的片上调试工具,支持60+调试适配器和8大处理器架构。它提供三大核心功能:片上调试、在系统编程和边界扫描测试。作为嵌入式开发工具链的中间桥梁,OpenOCD连接上层IDE/GDB与底层硬件,采用分层架构设计实现硬件兼容性。其配置基于Tcl脚本语言,支持网络服务接口,广泛应用于ARM、RISC-V等芯片的调试与烧录场景。

从事嵌入式linux android驱动开发,拥有全栈能力 1398
上一篇: JProfiler使用入门(一)——准备工作
下一篇: JProfiler eclipse 整合配置
leminsky
博客等级 码龄22年 43粉丝 0原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值