文档章节

JreMemoryLeakPreventionListener引发的报错问题

T
 Tomax
发布于 2016/10/09 15:12
字数 717
阅读 44
收藏 0

There is a memory leak detection feature introduced in Tomcat 6.0.25 that attempts to log objects that have failed to be unregistered by webapps it hosts when they are stopped, and were forcibly unregistered by Tomcat. As Tomcat is forcibly removing these objects, it is not a serious concern that these log messages occur.

停止tomcat服务后,报出以下错误:

严重: The web application [] appears to have started a thread named [Timer-0] but has failed to stop it. This is very likely to create a memory leak.
2016-9-27 21:33:48 org.apache.catalina.loader.WebappClassLoader clearReferencesThreads
严重: The web application [] appears to have started a thread named [pool-1-thread-1] but has failed to stop it. This is very likely to create a memory leak.
2016-9-27 21:33:48 org.apache.catalina.loader.WebappClassLoader clearReferencesThreads
严重: The web application [] appears to have started a thread named [DefaultQuartzScheduler_Worker-2] but has failed to stop it. This is very likely to create a memory leak.
2016-9-27 21:33:48 org.apache.catalina.loader.WebappClassLoader clearReferencesThreads

初步诊断为服务停止时,线程池未能成功关闭,添加线程监听器ThreadListener,在服务停止的时候停止线程池:

public class ThreadListener implements ServletContextListener {

	private Log logger = LogFactory.getLog(ThreadListener.class);
	
	@Override
	public void contextInitialized(ServletContextEvent sce) {
		
	}

	@Override
	public void contextDestroyed(ServletContextEvent sce) {
		try {
			logger.info("销毁线程池");
			ProtoExecutorService.getExecutor().shutdownNow();
		} catch (Exception e) {
			logger.error(String.format("销毁线程池出错,错误信息:%s", e));
			e.printStackTrace();
		}
	}
}

继续运行一段时间后发现,停止tomcat服务后仍会出现同样报错,查找资料,http://stackoverflow.com/questions/5292349/is-this-very-likely-to-create-a-memory-leak-in-tomcat ,添加清理ThreadLocal的代码:

public class ThreadLocalImmolater {

	private Log logger = LogFactory.getLog(ThreadLocalImmolater.class);

	private static ThreadLocalImmolater immolater = null;
	
    Boolean debug;

    public ThreadLocalImmolater() {
        debug = false;
    }
    
    public synchronized static ThreadLocalImmolater getInstance(){
    	if(null == immolater){
    		immolater = new ThreadLocalImmolater();
    	}
    	return immolater;
    }
    
    public Integer immolate() throws Exception {
        int count = 0;
        final Field threadLocalsField = Thread.class.getDeclaredField("threadLocals");
        threadLocalsField.setAccessible(true);
        final Field inheritableThreadLocalsField = Thread.class.getDeclaredField("inheritableThreadLocals");
        inheritableThreadLocalsField.setAccessible(true);
        for (final Thread thread : Thread.getAllStackTraces().keySet()) {
            count += clear(threadLocalsField.get(thread));
            count += clear(inheritableThreadLocalsField.get(thread));
            
            if (thread != null) {
            	thread.setContextClassLoader(null);
            }
        }
        logger.info("immolated " + count + " values in ThreadLocals");
        return count;
    }

    private int clear(final Object threadLocalMap) throws Exception {
        if (threadLocalMap == null)
                return 0;
        int count = 0;
        final Field tableField = threadLocalMap.getClass().getDeclaredField("table");
        tableField.setAccessible(true);
        final Object table = tableField.get(threadLocalMap);
        for (int i = 0, length = Array.getLength(table); i < length; ++i) {
            final Object entry = Array.get(table, i);
            if (entry != null) {
                final Object threadLocal = ((WeakReference)entry).get();
                if (threadLocal != null) {
                    log(i, threadLocal);
                    Array.set(table, i, null);
                    ++count;
                }
            }
        }
        return count;
    }

    private void log(int i, final Object threadLocal) {
        if (!debug) {
            return;
        }
        if (threadLocal.getClass() != null &&
            threadLocal.getClass().getEnclosingClass() != null &&
            threadLocal.getClass().getEnclosingClass().getName() != null) {

            logger.info("threadLocalMap(" + i + "): " +
                        threadLocal.getClass().getEnclosingClass().getName());
        }
        else if (threadLocal.getClass() != null &&
                 threadLocal.getClass().getName() != null) {
            logger.info("threadLocalMap(" + i + "): " + threadLocal.getClass().getName());
        }
        else {
            logger.info("threadLocalMap(" + i + "): cannot identify threadlocal class name");
        }
    }

}

在ThreadListener中添加以下代码:

//清理线程
try {
	logger.info("清理线程");
	ThreadLocalImmolater.getInstance().immolate();
} catch (Exception e) {
	logger.error(String.format("清理线程出错,错误信息:%s", e));
	e.printStackTrace();
}

运行一段时间后发现,停止tomcat服务后不再出现同样错误,但是会出现

严重: The web application [] registered the JDBC driver [com.microsoft.sqlserver.jdbc.SQLServerDriver] but failed to unregister it when the web application was stopped. To prevent a memory leak, the JDBC Driver has been forcibly unregistered.

在ThreadListener中添加以下代码:

logger.info("关闭数据库连接");
Enumeration<Driver> drivers = DriverManager.getDrivers();
while (drivers.hasMoreElements()) {
	Driver driver = drivers.nextElement();
	try {
		DriverManager.deregisterDriver(driver);
		logger.info(String.format("deregistering jdbc driver: %s", driver));
	} catch (SQLException e) {
		logger.error(String.format("Error deregistering driver %s", driver), e);
	}

}

报错消失。

参考资料:

http://fourfireliu.iteye.com/blog/2187584

http://stackoverflow.com/questions/5292349/is-this-very-likely-to-create-a-memory-leak-in-tomcat

© 著作权归作者所有

共有 人打赏支持
下一篇: JVM性能调优
T
粉丝 0
博文 5
码字总数 4372
作品 0
西安
私信 提问
tomcat,JreMemoryLeakPreventionListener类执行DriverManager.getDrivers()作用

tomcat的JreMemoryLeakPreventionListener类有个疑问,程序里调用了DriverManager来防止不正确的加载。但是DriverManager属于jdk/lib目录下jar里的类,在tomcat的类加载模型里,线程进入web...

_鱼_
2017/12/06
122
1
Tomcat的JreMemoryLeakPreventionListener1小时执行一次fu...

工作遇到每小时一次的full gc问题,并且一次运行8秒,影响体验。故转来一篇日志,Mark一下 项目部署在Tomcat7上,操作系统是centOS5.5,打印出gc的日志,发现有些full gc在heap还很空余的时候...

来吧
2013/08/06
0
0
实现CStack类遇到的问题

自己动手编写一个CStack类,包括头文件CStack.h以及源文件CStack.cpp。 遇到了几个问题: 1.每个文件都要写using namespace std;没写的文件会报错:缺少类型说明符……(这不是废话吗。。可是...

shs0708
2016/04/18
44
0
Symfony2.5开发常见错误

最近正在用Symfony2.5框架写一个境外电子商务项目,搭配webseverse编写相关接口;还好对方已经提供了相关接口,我只用写前段接口就好,但是用Symfony2.5操作数据库也是相当简单的;我接触过相...

晓军知了
2014/12/08
0
0
Linux下Tomcat多部署形式,让每个项目维护起来互不影响

进入tomcat的bin目录下 cd /home/apache-tomcat-6.0.35/bin/ 此时一定要注意先将bin目录下的所有.sh的shell授予权限不然在执行时linux会提示错误 chmod 755 *.sh 接着执行./startup.sh 然后打...

LittlerBeans
2015/11/23
219
4

没有更多内容

加载失败,请刷新页面

加载更多

jquery通过id显示隐藏

var $div3 = $('#div3'); 显示 $div3.show(); 隐藏 $div3.hide();

yan_liu
今天
3
0
《乱世佳人》读书笔记及相关感悟3900字

《乱世佳人》读书笔记及相关感悟3900字: 之前一直听「荔枝」,后来不知怎的转向了「喜马拉雅」,一听就是三年。上班的时候听房产,买房了以后听装修,兴之所至时听旅行,分手后听亲密关系,...

原创小博客
今天
3
0
大数据教程(9.6)map端join实现

上一篇文章讲了mapreduce配合实现join,本节博主将讲述在map端的join实现; 一、需求 实现两个“表”的join操作,其中一个表数据量小,一个表很大,这种场景在实际中非常常见,比如“订单日志...

em_aaron
今天
3
0
cookie与session详解

session与cookie是什么? session与cookie属于一种会话控制技术.常用在身份识别,登录验证,数据传输等.举个例子,就像我们去超市买东西结账的时候,我们要拿出我们的会员卡才会获取优惠.这时...

士兵7
今天
3
0
十万个为什么之为什么大家都说dubbo

Dubbo是什么? 使用背景 dubbo为什么这么流行, 为什么大家都这么喜欢用dubbo; 通过了解分布式开发了解到, 为适应访问量暴增,业务拆分后, 子应用部署在多台服务器上,而多台服务器通过可以通过d...

尾生
今天
4
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部