使用Jprofiler来监控jvm的运行
最近几天,线上的积分服务器不停的报警重启
看了resin的log信息,既没有OutofMemory,也没有其它的异常
偶尔有几个“Too many open files”的异常
通过ulimit -a查看最大打开文件数,发现是1024,于是执行
调大打开文件数目,但还是没有作用,用lsof -p来查看对应的进程
有1000多个打开的文件,而且有很多sock文件,一直处于ESTAB状态,似乎没有释放
于是,开始怀疑是程序的某个地方有问题,造成resin的Thread堵塞
由于从resin的log里无法定位到具体的位置,所以就想到了用Jprofiler来调试
在Jprofiler里建立一个remote application后,就能监控服务器上resin的各种状态了
可以查看内存状态,cpu状态,线程状态,虚拟机的状态等
由于我怀疑是线程堵塞,所以就直接到Thread Views里查看线程情况
使用Thread Dump,Dump出某个时刻的所有线程
看到有很多如下的Thread:
- Thread resin-tcp-connection-127.0.0.1:6837-373:
- at sun.misc.Unsafe.park(boolean, long)
- at java.util.concurrent.locks.LockSupport.park()
- at java.util.concurrent.locks.AbstractQueuedSynchronizer.parkAndCheckInterrupt()
- at java.util.concurrent.locks.AbstractQueuedSynchronizer.doAcquireSharedInterruptibly(int)
- at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireSharedInterruptibly(int)
- at java.util.concurrent.Semaphore.acquire()
- 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出来,就能很快看出占用内存过大的方法
内存泄露基本上就是对应的方法造成的