- 1、原创力文档(book118)网站文档一经付费(服务费),不意味着购买了该文档的版权,仅供个人/单位学习、研究之用,不得用于商业用途,未经授权,严禁复制、发行、汇编、翻译或者网络传播等,侵权必究。。
- 2、本站所有内容均由合作方或网友上传,本站不对文档的完整性、权威性及其观点立场正确性做任何保证或承诺!文档内容仅供研究参考,付费前请自行鉴别。如您付费,意味着您自己接受本站规则且自行承担风险,本站不退款、不进行额外附加服务;查看《如何避免下载的几个坑》。如果您已付费下载过本站文档,您可以点击 这里二次下载。
- 3、如文档侵犯商业秘密、侵犯著作权、侵犯人身权等,请点击“版权申诉”(推荐),也可以打举报电话:400-050-0827(电话支持时间:9:00-18:30)。
- 4、该文档为VIP文档,如果想要下载,成为VIP会员后,下载免费。
- 5、成为VIP后,下载本文档将扣除1次下载权益。下载后,不支持退款、换文档。如有疑问请联系我们。
- 6、成为VIP后,您将拥有八大权益,权益包括:VIP文档下载权益、阅读免打扰、文档格式转换、高级专利检索、专属身份标志、高级客服、多端互通、版权登记。
- 7、VIP文档为合作方或网友上传,每下载1次, 网站将根据用户上传文档的质量评分、类型等,对文档贡献者给予高额补贴、流量扶持。如果你也想贡献VIP文档。上传文档
查看更多
看看人家那后端API接口写得,那叫一个优雅!
记录一次线上JVM堆外内存泄漏问题的排查过程与思路,其中夹带一些JVM内存安排机制以及*常用的JVM问题排查指令和工具共享*,期望对大家有所挂念。
?
在整个排查过程中,我也走了不少弯路,但是在文章中我仍旧会把完整的思路和想法写出来,当做一次阅历教训,给后人参考,文章最终也总结了下内存泄漏问题快速排查的几个准绳。
?
本文的次要内容:
毛病描述和排查过程
毛病缘由和处理方案分析
JVM堆内内存和堆外内存安排原理
常用的进程内存泄漏排查指令和工具引见和使用
毛病描述
?
8月12日半夜午休时间,我们商业服务收到告警,服务进程占用容器的物理内存(16G)超过了80%的阈值,并且还在不断上升。
?
?
监控系统调出图表查看:
?
?
像是Java进程发生了内存泄漏,而我们堆内存的限制是4G,这种大于4G快要吃满内存应当是JVM堆外内存泄漏。
?
确认了下当时服务进程的启动配置:
-Xms4g -Xmx4g -Xmn2g -Xss1024K -XX:PermSize=256m -XX:MaxPermSize=512m -XX:ParallelGCThreads=20 -XX:+UseConcMarkSweepGC -XX:+UseParNewGC -XX:+UseCMSCompactAtFullCollection -XX:CMSInitiatingOccupancyFraction=80
?
虽然当天没有上线新代码,但是当天上午我们正在使用消息队列推送历史数据的修复脚本,该任务会大量调用我们服务其中的某一个接口,所以初步怀疑和该接口有关。
?
下图是该调用接口当天的访问量变化:
?
?
可以看到案发当时调用量相比正常情况(每分钟200+次)提高了很多(每分钟5000+次)。
?
我们临时让脚本停止发送消息,该接口调用量下降到每分钟200+次,容器内存不再以极高斜率上升,一切好像恢复了正常。
?
接下来排查这个接口是不是发生了内存泄漏。
排查过程
?
首先我们先回顾下Java进程的内存安排,便利我们下面排查思路的阐述。
?
以我们线上使用的JDK1.8版本为例。JVM内存安排网上有很多总结,我就不再进行二次创作。
?
JVM内存区域的划分为两块:堆区和非堆区。
?
堆区:就是我们熟知的重生代老年月。
非堆区:非堆区如图中所示,有元数据区和直接内存。
?
?
这里需要额外留意的是:永久代(JDK8的原生去)存放JVM运转时使用的类,永久代的对象在full GC时进行垃圾收集。
?
复习完了JVM的内存安排,让我们回到毛病上来。
· 堆内存分析
?
虽说一开头就基本确认与堆内存无关,由于泄露的内存占用超过了堆内存限制4G,但是我们为了保险起见先看下堆内存有什么线索。
?
我们观看了重生代和老年月内存占用曲线以及回收次数统计,和平常一样没有大问题,我们接着在事故现场的容器上dump了一份JVM堆内存的日志。
· 堆内存Dump
?
堆内存快照dump命令:
jmap -dump:live,format=b,file=xxxx.hprof pid
?
画外音:你也可以使用jmap -histo:live pid直接查看堆内存存活的对象。
?
导出后,将Dump文件下载回本地,然后可以使用Eclipse的MAT(Memory Analyzer)或者JDK自带的JVisualVM打开日志文件。
?
使用MAT打开文件如图所示:
?
?
可以看到堆内存中,有一些nio有关的大对象,比如正在接收消息队列消息的nioChannel,还有nio.HeapByteBuffer,但是数量不多,不能作为推断的依据,先放着观看下。
?
下一步,我开头扫瞄该接口代码,接口内部次要规律是调用集团的WCS客户端,将数据库表中数据查表后写入WCS,没有其他额外规律
?
发觉没有什么特殊规律后,我开头怀疑WCS客户端封装能否存在内存泄漏,这样怀疑的理由是,WCS客户端底层是由SCF客户端封装的,作为RPC框架,其底层通讯传输协议有可能会申请直接内存。
?
是不是我的代码动身了WCS客户端的Bug,导致不断地申请直接内存的调用,最终吃满内存。
?
我联系上了WCS的值班人,将我们遇到的问题和他们描述了一下,他们回复我们,会在他们本地执行下写入操作的压测,看看能不能复现我们的问题。
?
既然等待他们的反馈还需要时间,我们就预备先本人揣摩下缘由。
?
我将怀疑的目光停留在了直接内存上,怀疑是由于接口调用量过大,客户端对nio使用不当,导致使用ByteBuffer申请过多的直接内存。
?
画外音:最终的结果证明,这一个先入为主的思路导致排查过程走了弯路。在问题的排查过程中,用合理的猜想来缩小排查范围是可以的,但最好先把每种可能性都列清
原创力文档


文档评论(0)