美文网首页
记一次生产内存泄漏问题

记一次生产内存泄漏问题

作者: jackyzr | 来源:发表于2018-09-22 00:01 被阅读0次

时间: 2018年3月16号晚

表现现象: 客户访问非常慢到最后无法打开

pinpoint请求: 请求逐步变慢(图1),持续Full GC&CPU占用率高(图2),出现OOM(图3

紧急措施: 加大内存、重启服务器
重现问题: 测试环境模拟并发访问(10线程&10000次/线程),开jmx端口&Virtual VM监控(图4),问题重现,启动两三分钟后开始出现GC,后续内存持续上涨,dump堆转储文件

分析问题: MAT(Memory Analyzer tool)分析,找泄露的代码

  1. 从MAT的分析可以看出, javax.crypto.JceSecurity 的实例占用了最多的堆内存(Retained Heap | 深堆) (图5

  2. 从dominated tree可以看到,javax.crypto.JceSecurity 的实例的retained heap占了73% (图6),主要是一个IdentityHashMap类型的属性verificationResults,放了很多org.bouncycastle.jce.provider.BouncyCastleProvider 对象, 每个的retained heap占用182712字节 (图7

  3. 另外从virtual vm看转储堆上的线程, 有很多BLOCKED的线程, 都卡在javax.crypto.JceSecurity.getVerificationResult(JceSecurity.java:173)图8),按现象看应该是在等待Full GC

  4. 从getVerificationResult可以看出, 只要新传入Provider都会放到verificationResults缓存起来,
    看调用链上(Rsa的decrypt 图11-> Cipher.getInstance 图12 -> JceSecurity.getVerificationResult 图13),Rsa的解密不应该每次重新new org.bouncycastle.jce.provider.BouncyCastleProvider 对象。

  5. BouncyCastleProvider的问题(图1213):

a. provider自己是一个java.util.Properties,将所有的预设的provider的key, value都作为property put到自己的hashtable里;

b. 如果key, value都是string的话, 还将他们放到一个java.util.LinkedHashMap.LinkedHashMap<String,String>() 的属性 legacyStrings里;

c. 在java.security.Provider.getService(String, String) 的时候, 会把legacyStrings里所有的key,value解析成ServiceKey,Service对,放到另一个java.util.LinkedHashMap.LinkedHashMap<ServiceKey,Service>() 的属性legacyMap里

d. 因此,每次new BouncyCastleProvider 都会产生非常多的对象和引用(占用182712字节),且缓存在JceSecurity的verificationResults没法释放。

解决问题: 按照BouncyCastleProvider 的注释,改代码,将BouncyCastleProvider实例对象作为Rsa的静态成员变量可以解决问题。

验证上线: 更改后再验证(图14),内存使用正常,CPU正常

备 注: 其实, 在重现问题,设置jmx端口,用jmeter测试的时候,已经开始在看代码, 因为最近加就只加了解密的代码,除了Cipher.getInstance("RSA", new org.bouncycastle.jce.provider.BouncyCastleProvider()); 这句,其他地方看不出来会出现内存泄露,于是,顺着看下去,就看到javax.crypto.JceSecurity.getVerificationResult 里的缓存,回头看了下BouncyCastleProvider就确定怀疑正确。 然后紧急版本线上了再说。virtual vm和MAT的截图都是后续再分析时候截的。

<span id="图1">图1</span>


response_from_pinpointresponse_from_pinpoint

<span id="图2">图2</span>


full_gc_oomfull_gc_oom

<span id="图3">图3</span>


oom_of_pinpoint_traceoom_of_pinpoint_trace

<span id="图4">图4</span>


monitor_by_virtualvmmonitor_by_virtualvm

<span id="图5">图5</span>


mat_analyze_summarymat_analyze_summary

<span id="图6">图6</span>


mat_dominator_treemat_dominator_tree

<span id="图7">图7</span>


mat_list_objects_of_jcesecuritymat_list_objects_of_jcesecurity

<span id="图8">图8</span>


virtualvm_thread_blockedvirtualvm_thread_blocked

<span id="图9">图9</span>


jcesecurity_getverifycationresultjcesecurity_getverifycationresult

<span id="图10">图10</span>


cipher_getinstancecipher_getinstance

<span id="图11">图11</span>


bad_codebad_code

<span id="图12">图12</span>


bouncycastleprovilderbouncycastleprovilder

<span id="图13">图13</span>


jcesecurity_three_mapjcesecurity_three_map

<span id="图14">图14</span>


solve_the_problemsolve_the_problem

相关文章

  • 记一次生产内存泄漏问题

    时间: 2018年3月16号晚 表现现象: 客户访问非常慢到最后无法打开 pinpoint请求: 请求逐步变慢...

  • JDK的bin下的工具有哪些功能

    Java生产环境下问题排查 Java内存泄漏分析系列之一:使用jstack定位线程堆栈信息 Java内存泄漏分析系...

  • Xcode调试工具

    一.静态内存分析工具 编译阶段查找内存泄漏等问题 1.常见内存泄漏问题 常见的内存泄漏除了循环引用,CoreFou...

  • 记一次解决生产环境内存泄漏问题

    场景描述 生产环境应用服务在运行过程中,内存使用量不断升高,并且没有下降的趋势。由服务刚启动时10%左右的使用率,...

  • 记一次内存告警

    个人博客原文:记一次内存告警 今天给大家分享一次生产上遇到的内存问题。 生产上的一个应用经常运行一段时间后就内存告...

  • 三个方法帮助解决Android内存泄漏问题

    三个方法帮助解决Android内存泄漏问题 最近自己遇到了好几个内存泄漏的问题,也帮同事解决了几个内存泄漏的问题记...

  • 当Tomcat遇上Netty,我这一系列神操作,同事看了拍手叫绝

    故事背景 嘀嘀嘀~,生产事故,内存泄漏! 昨天下午,突然收到运维的消息,分部某系统生产环境内存泄漏了,帮忙排查一下...

  • 记一次内存泄漏问题排查

    问题描述某应用上线几天后,出现了访问速度非常慢的情况,通过日志发现是堆内存溢出错误:java.lang.OutOf...

  • 内存泄漏和内存溢出的区别与解决方式

    内存泄漏(memory leak ) 是指程序在申请内存后,无法释放已申请的内存空间就造成了内存泄漏,一次内存泄漏...

  • 安卓内存泄漏

    Android 内存泄漏总结 内存管理的目的就是让我们在开发中怎么有效的避免我们的应用出现内存泄漏的问题。内存泄漏...

网友评论

      本文标题:记一次生产内存泄漏问题

      本文链接:https://www.haomeiwen.com/subject/yyrtoftx.html