打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
解决com.mysql.jdbc.NonRegisteringDriver的内存泄漏

因为游戏的服务端是用Java编写的,大量使用了缓存和数据异步写入机制,但在运行的过程中要大量记录运营日志,所以数据库的读写虽然可能不像web服务器那样频繁,但数据库的开销其实还是相对可观的。上线运营一段时间后,服务器越来越卡,而且还出现Out Of Memory的情况。

         分析一:使用jmap命令观察到Jvm的GC已经到了很危险的情况,JVM的新生代和老年代都几乎已经消耗完毕了,如下图。

分析二:继续查看JVM 的GC日志,下面摘抄几条:

 2014-05-16T13:57:23.958+0800:592015.629: [Full GC 1948862K->1943518K(2024256K), 0.8818560 secs]

2014-05-16T13:58:10.682+0800: 592062.352:[Full GC 1948862K->1943638K(2024256K), 1.0139730 secs]

2014-05-16T13:59:18.427+0800: 592130.097:[Full GC 1948862K->1943686K(2024256K), 0.9705680 secs]

FULL GC出现的情况越来越频繁, 到了最后隔几秒就要Full GC一次,而且所需要的时间越来越长,Minor GC 已经几乎不出现了,与上图中的情况完全吻合。

         分析三:使用jmap-dump:format=b,file=logic_heap.hprof  pid这个命令,dump出内存的映像状态文件,再使用MemoryAnalyzer这个工具分析。发现有大量的com.MySQL.jdbc.NonRegisteringDriver这个对象产生泄漏。这个类是MySQL的connector/J官方驱动,按道理是不用出大问题的,我一开始也是从来没怀疑过,而且也不想去碰里面的代码。于是一直分析mybatis的代码,再分析自己封装的dao层。到了最后,实在没办法了,只能把connector/J的源代码打开,发现了里面有一个很重要的变量

ConcurrentHashMap<ConnectionPhantomReference,ConnectionPhantomReference>connectionPhantomRefs

这个map保存了所有连接的实例的虚引用(PhantomReference),然后由AbandonedConnectionCleanupThread不断释放,但最关键的是,似乎PhantomReference的特性是只有当主动调用System.gc()这个方法时才会主动释放(可能我说得不对,但据我观察的情况确定是这样)。而由于之前从一些jvm的调优文章里看到建议不要主动调用System.gc(),因此我整个项目里都从来没主动调用过System.gc()。

最后,解决方法很简单,只要自己写一个定时器,隔一段时间执行一下,就可以源源不断地清理这些PhantomReference



本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
【热】打开小程序,算一算2024你的财运
线上问题分析系列:数据库连接池内存泄漏问题的分析和解决方案
数据库连接池配置错误导致OOM
理解 Java 的 GC 与 幽灵引用
Java reference的种类及使用场景
Reference 、ReferenceQueue 详解
Java之GC机制
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服