您的位置:首页 > 运维架构

openfire线程暴增导致堆溢出服务器宕机排查处理

2017-04-02 17:34 495 查看
软件环境

openfire_src_4_0_2基础上二次开发 、   jdk1.7.x、 visualVM1.3.8

问题现象

有20来个内部试用用户进行访问openfire,启动一段时间后,客户端的访问体验越来越卡顿。大约半天的时间后,openfire服务器就报出堆溢出错误,无法再响应客户端的请求。偶尔有一次报出了线程溢出异常:java.lang.OutOfMemoryError: unable to create new native thread。

原因分析

首先查看服务端的日志,堆溢出并不是固定在某段特定代码的内存造成的。所以进一步使用visualVM来监控内存和线程情况进行分析。

对于使用visualVM来监控远程java应用的步骤请参考:http://blog.csdn.net/jeff_fangji/article/details/40070785

重启openfire一段时间后监控到如下的内存和线程情况:



在服务器中top出如下的信息:



结合两图来看,堆内存只用了500多MB,加上非堆、永久代的内存量才700多MB,而查询到的linux服务器中的物理内存使用了1.4GB,多出来的700多MB是怎么产生的呢?接着看线程数。一看吓一跳,有7000多个线程存活。这就解释了多出的700MB内存是怎么来的,那就可以确定问题所在了,是由线程泄露所引起的。

接下来要要确定具体是由什么线程所引起的,打开jvisualvm面板,发现好多线程名称都是一样的(因为采用了java的线程池Executors的创建线程池方法,默认的线程池名称是一样的),所以要重新命名线程,暂时没找到完美的解决办法,但可以采用如下较为麻烦的办法:ThreadPoolExecutor中运行线程名称的修改,实现想法:很简单在具体的线程执行方法开头中重新设置名称。

这样就可以使用visualvm很直观地把线程执行情况一览无余,暴增的线程就很容易找到,同时通过线程的执行状态,可以发现线程执行有性能上的潜在问题(比如:mina的业务执行是由IOHandler线程池的线程来处理的,若是有些线程处于执行状态的时间太长,便可说明这个业务的处理可能有潜在的性能问题)。

最后找到了问题线程的实现代码,发现这段创建线程池的方法没有使用单例,造成了一直创建线程池,导致线程暴增。

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

附上经历过的服务器宕机问题的经验总结

宕机因素:

1.资源不足(线程数、内存、文件限制链接符数、线程数过多引起内存不足、磁盘空间不足);

2.线程异常(程序错误引起、输入参数引起);

造成宕机最常见的程序异常

1.内存/线程等资源泄露;

2.多线程概率性错误;

3.数据库性能问题(查询慢、插入慢等)
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: