Java_内存泄漏_实例1

Posted 天使未必在场

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java_内存泄漏_实例1相关的知识,希望对你有一定的参考价值。

  版权声明:本文为博主原创文章,转载请注明出处。 


  记一次压测时Java内存泄漏问题的发现过程(2017-08-14)

【前篇】

  ①20170811进行A系统与B系统之间的会话功能进行压测,加上脚本准备期间的聊天消息,预计累计聊天30w+条消息;

  ②20170814原计划加大量对会话功能进行压测,情况如下;

【应用表现】

  ①B系统前台打开报错“504”;

 

  ②查看后台应用CPU情况,CPU利用率高达700+%(8核);

 

  ③查看后台内存情况,持续FullGC,且一次FullGC的时长在9s左右,从这里可以粗略定位CPU高的原因是内存GC问题导致;

 

【查看应用JVM配置】

  ①请教B开发团队,loader提到应该不是JVM配置引起的问题;

【尝试进行分析】

  ①尝试使用jvisualvm进行“堆 dump”,但是因为没有内存了所以jvisualvm连接后卡死(之前测试可以正确连接并显示JVM情况);

  ②使用jmap命令“jmap -dump:format=b,file=heap.hprof pid”进行dump,dump文件有16G(修改mat配置,无奈客户端硬件差);

  ③尝试shutdown应用后重启,无法shutdown;最后使用“kill -9 pid”暴力解决无法shutdown的情况,后重启应用;

【重启后情况】

  ①使用jvisualvm查看堆内存使用情况,表现为“堆内存持续上升”;

 

  ②重启1小时后,dump文件进行分析,其中“java.util.concurrent.LinkedBlockingQueue$Node”占用内存高达1G,基本可以判断存在“内存泄漏”;

 

  “com.best.oasis.B.common.entity.messageTransship.MessageTransship”对象151MB,且有160w个MessageTransship对象;

  ③B开发Review代码:原因所在:线程池中等待执行的任务队列存在内存泄漏的问题;

正常情况:

  A应用服务器发送消息给B服务器后,B服务器接收消息后将该消息存于中间表B_messagetransship中,同时将该消息转发给B客服端,B客服端接收消息并对该条消息进行ack,ack成功后删除B_messagetransship中的该条消息。为了防止消息丢失,B有一个定时重发job,用于每隔5s将B_messagetransship表中的消息再次推送一次;

异常情况:

  1.A服务器发送给B服务器的消息存在于B_messagetransship表中后(此时状态为“PENDING_SEND”),因为网络/B客户主动退出等问题,致使B客户端并未收到来自B服务器的该消息,则该消息的状态被置为“SEND_FAILED”存在表B_messagetransship中;

  2.A服务器发送给B服务器的消息,B客服端正确收到,但是B客服端发送的ACK请求返回失败,则该消息的状态被置为“PENDING_ACK”存在表B_messagetransship中;

失败消息定时重发实现逻辑:

  每隔5s从B_messagetransship中逐个取出失败的消息记录,以链式队列的形式链接在等待执行的任务队列中,若5s内该消息被线程处理且推送状态为成功,则删除数据库表中该消息记录;若5s内该消息被线程处理但推送状态为失败,则数据库表中的该条消息记录保持不变;若5s内该消息并未来得及被线程处理,下一次定时重发任务触发时,该消息会保留第二个拷贝在待处理任务队列中,以此类推;

bug发现的诱因:

  B_messagetransship表失败推送的消息量比较大,B_messagetransship表11w+条数据,失败消息量大的原因:

  ①11907条“再见”,状态为:SEND_FAILED

  产生原因:B客户端对话完毕未接收到再见语,就发起了“{"type":"close","sid":"${sid}"}”的请求,该现象在实际中也可能产生;

  ②17120条“很高兴为您服务”,状态为:PENDING_ACK

  产生原因:压测脚本未对“很高兴为您服务”消息进行ack;

  ③剩余的8w+条,为A发送给B的对话消息,推测是在脚本准备期间产生的数据;

开发下期优化思路:

  ①为B_messagetransship表中的消息增加生存时长,若超时则直接删除;

  ②限制待执行任务队列中messageTransship对象的数量,达到一定个数则不再从B_messagetransship中获取;

测试脚本修改:

  ①增加对“开始语”与“结束语”消息的ack;

以上是关于Java_内存泄漏_实例1的主要内容,如果未能解决你的问题,请参考以下文章

如何修复 _NSCFNumber 的 iOS 内存泄漏?

_CrtSetBreakAlloc 内存泄漏

javaThreadLocal 内存泄漏 代码演示 实例演示

ARC CCSprite 内存泄漏

可以在 Visual Studio 的泄漏检测中隐藏安全的内存泄漏吗?

开玩笑的猫鼬导致内存泄漏