打开APP
userphoto
未登录

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

开通VIP
Netty HashedWheelTimer过多导致内存泄漏的排错

背景:

CentOS release 5.6 (Final)

Netty 3.6.5 final

 

 

在一次压力测试中,发现Netty Based服务器连上4500+的clients就开始一直FullGC。

GC日志:

 

 

Java代码  
  1. 2013-07-01T09:24:52.328+0800: 227629.120: [Full GC [PSYoungGen: 116544K->112471K(233024K)] [ParOldGen: 699071K->699071K(699072K)] 815615K->811543K(932096K) [PSPermGen: 15071K->15056K(21248K)], 0.6043590 secs] [Times: user=2.34 sys=0.00, real=0.60 secs]   
  2. 2013-07-01T09:24:52.961+0800: 227629.753: [Full GC [PSYoungGen: 116544K->112514K(233024K)] [ParOldGen: 699071K->699071K(699072K)] 815615K->811586K(932096K) [PSPermGen: 15056K->15056K(21248K)], 0.6133040 secs] [Times: user=2.37 sys=0.00, real=0.61 secs]   

 

 

看出来年老代已经腾不出空间了。结果很明显,有对象导致了内存泄漏。

 

 

Java代码  
  1. jmap -histo XXXX  

 查看堆使用情况

 

 

Java代码  
  1. num     #instances         #bytes  class name  
  2. ---------------------------------------------  
  3.   1:      10252320      410092800  org.jboss.netty.util.internal.ConcurrentIdentityHashMap$Segment  
  4.   2:      10332783      330649056  java.util.concurrent.locks.ReentrantLock$NonfairSync  
  5.   3:      10252320      328462016  [Lorg.jboss.netty.util.internal.ConcurrentIdentityHashMap$HashEntry;  
  6.   4:       2563074      123027552  org.jboss.netty.util.internal.ConcurrentIdentityHashMap  
  7.   5:       2563072      123027456  org.jboss.netty.util.internal.ConcurrentIdentityHashMap$KeyIterator  
  8.   6:       2563074       82018464  [Lorg.jboss.netty.util.internal.ConcurrentIdentityHashMap$Segment;  
  9.   7:       2563072       41009152  org.jboss.netty.util.MapBackedSet  
  10.   8:       2563072       41009152  org.jboss.netty.util.internal.ConcurrentIdentityHashMap$KeySet  
  11.   9:        258183       12392784  org.jboss.netty.util.HashedWheelTimer$HashedWheelTimeout  

 

看第一行,有10252320 个 org.jboss.netty.util.internal.ConcurrentIdentityHashMap$Segment 对象!

 

同时发现cpu的占用非常平凡

于是查看线程情况,看到很多类似下面的timer线程:

 

Java代码  
  1. jstack XXX  

 

Java代码  
  1. "Hashed wheel timer #9086" prio=10 tid=0x00002aab886a7000 nid=0xe9f waiting on condition [0x00002aaba4380000]  
  2.    java.lang.Thread.State: TIMED_WAITING (sleeping)  
  3.         at java.lang.Thread.sleep(Native Method)  
  4.         at org.jboss.netty.util.HashedWheelTimer$Worker.waitForNextTick(HashedWheelTimer.java:504)  
  5.         at org.jboss.netty.util.HashedWheelTimer$Worker.run(HashedWheelTimer.java:402)  
  6.         at org.jboss.netty.util.ThreadRenamingRunnable.run(ThreadRenamingRunnable.java:108)  
  7.         at java.lang.Thread.run(Thread.java:722)  

 

 

发现很多timer线程,足足有5006个。

 

思考:测试压了5000个链接,也就是说timer/channel。可能这两者有关联,先解决timer问题。

 

查看new HashedWheelTimer的代码,发现有一处代码在每次连接时new了一个HashedWheelTimer,但是没有使用,fix it。(当然过程稍微复杂,没写的这么简单)

 

接着想线程跟内存泄漏的联系,看源码最实际,于是发现了这些timer是怎么把内存吃掉的。

 

默认每个Wheel有512个槽位,每个槽是一个MapBackedSet,每个MapBackedSet包含一个ConcurrentIdentityHashMap,每个ConcurrentIdentityHashMap默认大小为4。

 

 

Java代码  
  1. public HashedWheelTimer(  
  2.             ThreadFactory threadFactory, long tickDuration, TimeUnit unit) {  
  3.         this(threadFactory, tickDuration, unit, 512);  
  4.     }  

 

 

Java代码  
  1. for (int i = 0; i < wheel.length; i ++) {  
  2.             wheel[i] = new MapBackedSet<HashedWheelTimeout>(  
  3.                     new ConcurrentIdentityHashMap<HashedWheelTimeout, Boolean>(16, 0.95f, 4));  
  4.         }  

 

512 × 5000 × 4 = 10240000

 

很接近于10252320这个数字。OK,所有问题都解决了~!

本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
【热】打开小程序,算一算2024你的财运
Netty
定时器有几种实现方式?
java应用服务框架mina和netty应用案例都有哪些,两者该怎么选择?
Android之向中国天气网发送GET请求获取JSON数据实例
事件管道模型
Java实现定时任务的三种方法
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服