java hashed wheel timer netty_Netty HashedWheelTimer过多导致内存泄漏的排错

背景:

CentOS release 5.6 (Final)

Netty 3.6.5 final

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

GC日志:

Java代码 48794396_1.png2013-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]

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代码 48794396_1.pngjmap -histo XXXX

查看堆使用情况

Java代码 48794396_1.pngnum     #instances         #bytes  class name

---------------------------------------------

1:      10252320      410092800  org.jboss.netty.util.internal.ConcurrentIdentityHashMap$Segment

2:      10332783      330649056  java.util.concurrent.locks.ReentrantLock$NonfairSync

3:      10252320      328462016  [Lorg.jboss.netty.util.internal.ConcurrentIdentityHashMap$HashEntry;

4:       2563074      123027552  org.jboss.netty.util.internal.ConcurrentIdentityHashMap

5:       2563072      123027456  org.jboss.netty.util.internal.ConcurrentIdentityHashMap$KeyIterator

6:       2563074       82018464  [Lorg.jboss.netty.util.internal.ConcurrentIdentityHashMap$Segment;

7:       2563072       41009152  org.jboss.netty.util.MapBackedSet

8:       2563072       41009152  org.jboss.netty.util.internal.ConcurrentIdentityHashMap$KeySet

9:        258183       12392784  org.jboss.netty.util.HashedWheelTimer$HashedWheelTimeout

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

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

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

Java代码 48794396_1.pngjstack XXX

Java代码 48794396_1.png"Hashed wheel timer #9086" prio=10 tid=0x00002aab886a7000 nid=0xe9f waiting on condition [0x00002aaba4380000]

java.lang.Thread.State: TIMED_WAITING (sleeping)

at java.lang.Thread.sleep(Native Method)

at org.jboss.netty.util.HashedWheelTimer$Worker.waitForNextTick(HashedWheelTimer.java:504)

at org.jboss.netty.util.HashedWheelTimer$Worker.run(HashedWheelTimer.java:402)

at org.jboss.netty.util.ThreadRenamingRunnable.run(ThreadRenamingRunnable.java:108)

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代码 48794396_1.pngpublic HashedWheelTimer(

ThreadFactory threadFactory, long tickDuration, TimeUnit unit) {

this(threadFactory, tickDuration, unit, 512);

}

Java代码 48794396_1.pngfor (int i = 0; i 

wheel[i] = new MapBackedSet(

new ConcurrentIdentityHashMap(16, 0.95f, 4));

}

512 × 5000 × 4 = 10240000

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

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值