java 内存泄露 例子_Java_内存泄漏_实例1

本文记录了一次Java应用在压测时遇到的内存泄漏问题。通过分析CPU和内存使用情况,发现`LinkedBlockingQueue$Node`和`MessageTransship`对象占用大量内存,揭示了线程池中等待执行的任务队列存在内存泄漏。问题源于消息未被正确ACK导致的消息在B_messagetransship表中不断积累,进而影响系统性能。开发团队提出了优化策略,包括设置消息生存时长和限制任务队列大小。
摘要由CSDN通过智能技术生成

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

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

【前篇】

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

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

【应用表现】

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

d0e23283ffd8640d83cf6edeb1cd48ce.png

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

5fad3ac3286bc0f43e13d218073e385d.png

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

50d1fcb3f4dc2c370d9567669492efa6.png

【查看应用JVM配置】

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

2245199c74958fa2f1fba8505961875a.png

【尝试进行分析】

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

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

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

【重启后情况】

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

cbd776bd5d9888d50c3514c0f489a77f.png

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

6e0ac3f633b9a58fc75dee5f09506c4a.png

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

711a054530556915cd155e8a7c19ff27.png

③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内该消息并未来得及被线程处理,下一次定时重发任务触发时,该消息会保留第二个拷贝在待处理任务队列中,以此类推;

e8abbbf9beddfd9bb9a2940e509ba1a4.png

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;

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值