文档章节

JreMemoryLeakPreventionListener引发的报错问题

T
 Tomax
发布于 2016/10/09 15:12
字数 717
阅读 1.2K
收藏 1

#程序员薪资揭榜#你做程序员几年了?月薪多少?发量还在么?>>>

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
粉丝 1
博文 5
码字总数 4372
作品 0
西安
私信 提问
加载中

评论(0)

tomcat,JreMemoryLeakPreventionListener类执行DriverManager.getDrivers()作用

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

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

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

来吧
2013/08/06
1.7K
0
java.lang.ArrayStoreException: sun.reflect.annotation.TypeNotPresentExceptionProxy

将某个项目从Spring Boot1升级Spring Boot2之后出现如下报错,查了很多不同的解决方法都没有解决: Spring boot2项目启动时遇到了异常: java.lang.ArrayStoreException: sun.reflect.annot...

osc_m2bqaiwa
2019/10/21
12
0
深入分析Spring Boot2,解决 java.lang.ArrayStoreException异常

将某个项目从Spring Boot1升级Spring Boot2之后出现如下报错,查了很多不同的解决方法都没有解决: Spring boot2项目启动时遇到了异常: java.lang.ArrayStoreException: sun.reflect.annot...

osc_xxbg6mig
2018/09/27
5
0
LitePal学习(六)——多线程操作存在的问题

前言 LitePal数据库是一个不错的数据库框架。使用异常方便,但是当存储等操作涉及到多线程 的时候,就会引发资源被占用的问题。那么今天就来讲讲这个问题吧。 今天涉及的内容: 我数据查询代...

奔跑的佩恩
2019/12/07
0
0

没有更多内容

加载失败,请刷新页面

加载更多

Docker入门:什么是 Docker ?

Docker 解决了软件环境部署复杂的问题。 对于一个传统的软件工程,开发人员把写好的代码放到服务器上去运行是一件很头疼的事情,因为常常会出现环境不兼容而导致各种各样的 Bug。 比如说,开...

开源仔
17分钟前
22
1
idea激活教程,最新!!!

1.下载破解补丁(关键)。 破解补丁:JetbrainsIdesCrack-4.2-release.jar 百度云地址:https://pan.baidu.com/s/18ovphd7sm7oYXQb4CInaUg 提取码:cw2j 2.寻找到idea的安装目录,将下载下来...

osc_lgbm94am
17分钟前
26
0
共同创业五年,技术总监却突然就这么离职了

一、 引子 有一天,跟一位原同事老A聊起职场的一些情况,期间无意中提到了原公司的技术总监。我说这位技术总监带领公司从一家十几人的小团队,做到四百人的公司,作为同样都是开发者,而且以...

osc_5k0epejp
18分钟前
18
0
Python 中国象棋源码 V1

Pygame 做的中国象棋,一直以来喜欢下象棋,写了 python 就拿来做一个试试,水平有限,电脑走法水平低,需要在下次版本中更新电脑走法,希望源码能帮助大家更好的学习 python。总共分为四个文...

osc_wbienwab
20分钟前
26
0
flac是什么格式?flac无法正常播放怎么办?

相比以前的磁带和光碟,现如今听音乐可就简单方便多了,直接从音乐网站上下载歌曲就可以了。当然,不同的网站,下载下来的音乐格式可能是不一样的。除了咱们比较熟悉的MP3之外,网上下载下来...

深蓝月上
20分钟前
23
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部