最近几天,线上的积分服务器不停的报警重启


看了resin的log信息,既没有OutofMemory,也没有其它的异常


偶尔有几个“Too many open files”的异常


通过ulimit -a查看最大打开文件数,发现是1024,于是执行


ulimit -SHn 65536


调大打开文件数目,但还是没有作用,用lsof -p来查看对应的进程


有1000多个打开的文件,而且有很多sock文件,一直处于ESTAB状态,似乎没有释放


于是,开始怀疑是程序的某个地方有问题,造成resin的Thread堵塞


由于从resin的log里无法定位到具体的位置,所以就想到了用Jprofiler来调试


在Jprofiler里建立一个remote application后,就能监控服务器上resin的各种状态了


可以查看内存状态,cpu状态,线程状态,虚拟机的状态等


由于我怀疑是线程堵塞,所以就直接到Thread Views里查看线程情况


使用Thread Dump,Dump出某个时刻的所有线程


看到有很多如下的Thread:



折叠复制代码




  1. Thread resin-tcp-connection-127.0.0.1:6837-373:   

  2.   at sun.misc.Unsafe.park(boolean, long)  

  3.   at java.util.concurrent.locks.LockSupport.park()  

  4.   at java.util.concurrent.locks.AbstractQueuedSynchronizer.parkAndCheckInterrupt()  

  5.   at java.util.concurrent.locks.AbstractQueuedSynchronizer.doAcquireSharedInterruptibly(int)  

  6.   at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireSharedInterruptibly(int)  

  7.   at java.util.concurrent.Semaphore.acquire()  

  8.   at com.sohu.score.common.SubScoreSocketPool.subScore(java.lang.String, int)  






很明显,是方法subScore出问题了,造成一堆的Thread堵在那个地方,不释放资源,把resin给堵死了


然后,在对应的方法里加上debug log,最终很快就找出了错误所在


原来的程序使用了信号量semaphore来获取连接,对于socket结果正常,会release对应的信号量


但当socket返回错误信息时,程序没有release对应的semaphore就直接return了,导致semaphore很快被用完了


很多thread堵塞在了Semaphore.acquire() 地方


修改了程序后,Resin就运行正常了...


对于程序中的内存泄露,使用Jprofiler也能很容易的查出来


只要我们把某个时刻的heap给dump出来,就能很快看出占用内存过大的方法


内存泄露基本上就是对应的方法造成的