Jfinal +QuartzPlugin+Tomcat 整合后部署会内存溢出

在使用Jfinal 2.0 的整合一个定时任务的插件后 。将工程打包 ,部署到Tomcat,启动之后 ,控制台就会报错,显示是在Tomcat 关闭的时候有线程未被关闭,会导致内存溢出,完整报错信息如下:


三月 05, 2017 3:04:50 下午 org.apache.catalina.startup.VersionLoggerListener log

信息: Server version:        Apache Tomcat/7.0.61

三月 05, 2017 3:04:50 下午 org.apache.catalina.startup.VersionLoggerListener log

信息: Server built:          Mar 27 2015 12:03:56 UTC

三月 05, 2017 3:04:50 下午 org.apache.catalina.startup.VersionLoggerListener log

信息: Server number:         7.0.61.0

三月 05, 2017 3:04:50 下午 org.apache.catalina.startup.VersionLoggerListener log

信息: OS Name:               Windows 10

三月 05, 2017 3:04:50 下午 org.apache.catalina.startup.VersionLoggerListener log

信息: OS Version:            10.0

三月 05, 2017 3:04:50 下午 org.apache.catalina.startup.VersionLoggerListener log

信息: Architecture:          amd64

三月 05, 2017 3:04:50 下午 org.apache.catalina.startup.VersionLoggerListener log

信息: Java Home:             D:\softposition\java\jdk_1.8.0_111\jre

三月 05, 2017 3:04:50 下午 org.apache.catalina.startup.VersionLoggerListener log

信息: JVM Version:           1.8.0_111-b14

三月 05, 2017 3:04:50 下午 org.apache.catalina.startup.VersionLoggerListener log

信息: JVM Vendor:            Oracle Corporation

三月 05, 2017 3:04:50 下午 org.apache.catalina.startup.VersionLoggerListener log

信息: CATALINA_BASE:         D:\apache-tomcat-7.0.61

三月 05, 2017 3:04:50 下午 org.apache.catalina.startup.VersionLoggerListener log

信息: CATALINA_HOME:         D:\apache-tomcat-7.0.61

三月 05, 2017 3:04:50 下午 org.apache.catalina.startup.VersionLoggerListener log

信息: Command line argument: -Djava.util.logging.config.file=D:\apache-tomcat-7.0.61\conf\logging.properties

三月 05, 2017 3:04:50 下午 org.apache.catalina.startup.VersionLoggerListener log

信息: Command line argument: -Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager

三月 05, 2017 3:04:50 下午 org.apache.catalina.startup.VersionLoggerListener log

信息: Command line argument: -Djava.endorsed.dirs=D:\apache-tomcat-7.0.61\endorsed

三月 05, 2017 3:04:50 下午 org.apache.catalina.startup.VersionLoggerListener log

信息: Command line argument: -Dcatalina.base=D:\apache-tomcat-7.0.61

三月 05, 2017 3:04:50 下午 org.apache.catalina.startup.VersionLoggerListener log

信息: Command line argument: -Dcatalina.home=D:\apache-tomcat-7.0.61

三月 05, 2017 3:04:50 下午 org.apache.catalina.startup.VersionLoggerListener log

信息: Command line argument: -Djava.io.tmpdir=D:\apache-tomcat-7.0.61\temp

三月 05, 2017 3:04:50 下午 org.apache.catalina.core.AprLifecycleListener lifecycleEvent

信息: Loaded APR based Apache Tomcat Native library 1.1.33 using APR version 1.5.1.

三月 05, 2017 3:04:50 下午 org.apache.catalina.core.AprLifecycleListener lifecycleEvent

信息: APR capabilities: IPv6 [true], sendfile [true], accept filters [false], random [true].

三月 05, 2017 3:04:50 下午 org.apache.catalina.core.AprLifecycleListener initializeSSL

信息: OpenSSL successfully initialized (OpenSSL 1.0.1m 19 Mar 2015)

三月 05, 2017 3:04:50 下午 org.apache.coyote.AbstractProtocol init

信息: Initializing ProtocolHandler ["http-apr-80"]

三月 05, 2017 3:04:50 下午 org.apache.coyote.AbstractProtocol init

信息: Initializing ProtocolHandler ["ajp-apr-8009"]

三月 05, 2017 3:04:50 下午 org.apache.catalina.startup.Catalina load

信息: Initialization processed in 1150 ms

三月 05, 2017 3:04:50 下午 org.apache.catalina.core.StandardService startInternal

信息: Starting service Catalina

三月 05, 2017 3:04:50 下午 org.apache.catalina.core.StandardEngine startInternal

信息: Starting Servlet Engine: Apache Tomcat/7.0.61

三月 05, 2017 3:04:50 下午 org.apache.catalina.startup.HostConfig deployWAR

信息: Deploying web application archive D:\apache-tomcat-7.0.61\webapps\po.war

三月 05, 2017 3:04:51 下午 org.apache.catalina.loader.WebappClassLoader validateJarFile

信息: validateJarFile(D:\apache-tomcat-7.0.61\webapps\po\WEB-INF\lib\javax.servlet-3.0.0.v201112011016.jar) - jar not loaded. See Servlet Spec 3.0, section 10.7.2. Offending class: javax/servlet/Servlet.class

三月 05, 2017 3:04:52 下午 org.apache.catalina.startup.TaglibUriRule body

信息: TLD skipped. URI: http://shiro.apache.org/tags is already defined

SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder".

SLF4J: Defaulting to no-operation (NOP) logger implementation

SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details.

log4j:WARN No appenders could be found for logger (org.apache.commons.beanutils.converters.BooleanConverter).

log4j:WARN Please initialize the log4j system properly.

三月 05, 2017 3:04:54 下午 org.apache.catalina.core.StandardContext startInternal

严重: Error filterStart

三月 05, 2017 3:04:54 下午 org.apache.catalina.core.StandardContext startInternal

严重: Context [/po] startup failed due to previous eWebappClassLoader clearReferencesJdbc

严重: The web application [/po] registered the JDBC driver [com.alibaba.druid.proxy.DruidDriver] but failed to unregister it when the web application was stopped. To prevent a memory leak, the JDBC Driver has been forcibly unregistered.

三月 05, 2017 3:04:59 下午 org.apache.catalina.loader.WebappClassLoader clearReferencesJdbc

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

三月 05, 2017 3:04:59 下午 org.apache.catalina.loader.WebappClassLoader clearReferencesThreads

严重: The web application [/po] appears to have started a thread named [Druid-ConnectionPool-Create-1964019847] but has failed to stop it. This is very likely to create a memory leak.

三月 05, 2017 3:04:59 下午 org.apache.catalina.loader.WebappClassLoader clearReferencesThreads

严重: The web application [/po] appears to have started a thread named [Druid-ConnectionPool-Destroy-1964019847] but has failed to stop it. This is very likely to create a memory leak.

三月 05, 2017 3:04:59 下午 org.apache.catalina.loader.WebappClassLoader clearReferencesThreads

严重: The web application [/po] appears to have started a thread named [DefaultQuartzScheduler_Worker-1] but has failed to stop it. This is very likely to create a memory leak.

三月 05, 2017 3:04:59 下午 org.apache.catalina.loader.WebappClassLoader clearReferencesThreads

严重: The web application [/po] 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.

三月 05, 2017 3:04:59 下午 org.apache.catalina.loader.WebappClassLoader clearReferencesThreads

严重: The web application [/po] appears to have started a thread named [DefaultQuartzScheduler_Worker-3] but has failed to stop it. This is very likely to create a memory leak.

三月 05, 2017 3:04:59 下午 org.apache.catalina.loader.WebappClassLoader clearReferencesThreads

严重: The web application [/po] appears to have started a thread named [DefaultQuartzScheduler_Worker-4] but has failed to stop it. This is very likely to create a memory leak.

三月 05, 2017 3:04:59 下午 org.apache.catalina.loader.WebappClassLoader clearReferencesThreads

严重: The web application [/po] appears to have started a thread named [DefaultQuartzScheduler_Worker-5] but has failed to stop it. This is very likely to create a memory leak.

三月 05, 2017 3:04:59 下午 org.apache.catalina.loader.WebappClassLoader clearReferencesThreads

严重: The web application [/po] appears to have started a thread named [DefaultQuartzScheduler_Worker-6] but has failed to stop it. This is very likely to create a memory leak.

三月 05, 2017 3:04:59 下午 org.apache.catalina.loader.WebappClassLoader clearReferencesThreads

严重: The web application [/po] appears to have started a thread named [DefaultQuartzScheduler_Worker-7] but has failed to stop it. This is very likely to create a memory leak.

三月 05, 2017 3:04:59 下午 org.apache.catalina.loader.WebappClassLoader clearReferencesThreads

严重: The web application [/po] appears to have started a thread named [DefaultQuartzScheduler_Worker-8] but has failed to stop it. This is very likely to create a memory leak.

三月 05, 2017 3:04:59 下午 org.apache.catalina.loader.WebappClassLoader clearReferencesThreads

严重: The web application [/po] appears to have started a thread named [DefaultQuartzScheduler_Worker-9] but has failed to stop it. This is very likely to create a memory leak.

三月 05, 2017 3:04:59 下午 org.apache.catalina.loader.WebappClassLoader clearReferencesThreads

严重: The web application [/po] appears to have started a thread named [DefaultQuartzScheduler_Worker-10] but has failed to stop it. This is very likely to create a memory leak.

三月 05, 2017 3:04:59 下午 org.apache.catalina.loader.WebappClassLoader clearReferencesThreads

严重: The web application [/po] appears to have started a thread named [Timer-0] but has failed to stop it. This is very likely to create a memory leak.

三月 05, 2017 3:04:59 下午 org.apache.catalina.loader.WebappClassLoader clearReferencesThreads

严重: The web application [/po] appears to have started a thread named [DefaultQuartzScheduler_QuartzSchedulerThread] but has failed to stop it. This is very likely to create a memory leak.

三月 05, 2017 3:04:59 下午 org.apache.catalina.startup.HostConfig deployWAR

信息: Deployment of web application archive D:\apache-tomcat-7.0.61\webapps\po.war has finished in 8,323 ms

三月 05, 2017 3:04:59 下午 org.apache.catalina.startup.HostConfig deployDirectory

信息: Deploying web application directory D:\apache-tomcat-7.0.61\webapps\docs

三月 05, 2017 3:04:59 下午 org.apache.catalina.startup.HostConfig deployDirectory

信息: Deployment of web application directory D:\apache-tomcat-7.0.61\webapps\docs has finished in 63 ms

三月 05, 2017 3:04:59 下午 org.apache.catalina.startup.HostConfig deployDirectory

信息: Deploying web application directory D:\apache-tomcat-7.0.61\webapps\examples

三月 05, 2017 3:04:59 下午 org.apache.catalina.startup.HostConfig deployDirectory

信息: Deployment of web application directory D:\apache-tomcat-7.0.61\webapps\examples has finished in 250 ms

三月 05, 2017 3:04:59 下午 org.apache.catalina.startup.HostConfig deployDirectory

信息: Deploying web application directory D:\apache-tomcat-7.0.61\webapps\host-manager

三月 05, 2017 3:04:59 下午 org.apache.catalina.startup.HostConfig deployDirectory

信息: Deployment of web application directory D:\apache-tomcat-7.0.61\webapps\host-manager has finished in 47 ms

三月 05, 2017 3:04:59 下午 org.apache.catalina.startup.HostConfig deployDirectory

信息: Deploying web application directory D:\apache-tomcat-7.0.61\webapps\manager

三月 05, 2017 3:04:59 下午 org.apache.catalina.startuprrors

三月 05, 2017 3:04:59 下午 org.apache.catalina.loader..HostConfig deployDirectory

信息: Deployment of web application directory D:\apache-tomcat-7.0.61\webapps\manager has finished in 62 ms

三月 05, 2017 3:04:59 下午 org.apache.coyote.AbstractProtocol start

信息: Starting ProtocolHandler ["http-apr-80"]

三月 05, 2017 3:04:59 下午 org.apache.coyote.AbstractProtocol start

信息: Starting ProtocolHandler ["ajp-apr-8009"]

三月 05, 2017 3:04:59 下午 org.apache.catalina.startup.Catalina start

信息: Server startup in 8834 ms


评论区

JFinal

2017-03-05 15:46

这个异常是在表述,tomcat 在关闭时由于 JDBC 驱动 unregister 失败,为了避免内存泄漏对其进行了强制 unregister 操作

这种情况,通常是由于在项目之中存在非 daemon 类型的线程,所以在 tomcat 使用 shutdown 命令时并不能真正关闭 tomcat

解决办法极其简单,找到那个非 daemon 线程,将其改为 daemon 线程即可。寻找的办法可以是在 eclipse 时启动项目,观察所有启动的线程类型即可知道

天涯刀

2017-03-09 12:48

@JFinal 谢谢大神。我加了一个Tomcat 的关闭监听事件,在tomcat关闭的时候,自己主动的将那几个线程给关闭了。设置它们为守护线程的时候不太行,显示不给修改。

天涯刀

2017-03-13 17:09

@JFinal 非常抱歉,再次打扰您。我上次以为这个问题已经完美解决了,当时修改完之后,连续实际部署测试几次,也确实没有再发生内存溢出的问题。但是没想到今天再次打包进行部署的时候这个问题又一次发生了,这让我有了新的疑问。
1.Tomcat 在启动一个工程的时候,是不是没启动一个线程就会预先判断,该线程有没有结束的方法?没有就会报内存会溢出的警告.
2.上次的实现思路,是实现一个Tomcat关闭的监听事件,在Tomcat关闭的时候,找到这几个导致内存溢出的线程,强制将其关闭。是不是在时机上已经迟了?

另外:我在部署另一个项目时候也碰到了与此相类似的问题。查阅资料后发现有很多相似的案例,但是却没有发现十分完美的解决方案。
。。。(正常部分)
重: Error filterStart
三月 13, 2017 10:47:27 上午 org.apache.catalina.core.StandardContext startInternal
严重: Context [/wf] startup failed due to previous errors
三月 13, 2017 10:47:27 上午 org.apache.catalina.loader.WebappClassLoader clearReferencesJdbc
严重: The web application [/wf] registered the JDBC driver [com.alibaba.druid.proxy.DruidDriver] but failed to unregister it when the web application was stopped. To prevent a memory leak, the JDBC Driver has been forcibly unregistered.
三月 13, 2017 10:47:27 上午 org.apache.catalina.loader.WebappClassLoader clearReferencesJdbc
严重: The web application [/wf] registered the JDBC driver [com.mysql.jdbc.Driver] but failed to unregister it when the web application was stopped. To prevent a memory leak, the JDBC Driver has been forcibly unregistered.
三月 13, 2017 10:47:27 上午 org.apache.catalina.loader.WebappClassLoader clearReferencesThreads
严重: The web application [/wf] appears to have started a thread named [Druid-ConnectionPool-Create-2101937136] but has failed to stop it. This is very likely to create a memory leak.
三月 13, 2017 10:47:27 上午 org.apache.catalina.loader.WebappClassLoader clearReferencesThreads
严重: The web application [/wf] appears to have started a thread named [Druid-ConnectionPool-Destroy-2101937136] but has failed to stop it. This is very likely to create a memory leak.
。。。(正常部分)

这两个问题能算是同一个问题吗?
万分期盼您能拨空指点一下。

JFinal

2017-03-13 17:27

@天涯刀 异常提示仍然是同一个问题

最简的解决办法是将线程给搞成 deamon 的,方法很简单,在 new Thread 的时候,传入一个 true 参数即可

其它解决方案,可以是使用一个控制变量,使线程可以完全退出。回到具体的两个问题:
1:tomcat 不是在启动的时候判断,而是在 shutdown 的时候判断是否有线程没有退出
2:要看你的监听事件的事处理方式,例如,是不是在同一个线程中处理的,如果是独立的线程之中,那么 tomcat 线程继续它自己的 shutdown 线程,而其它非 deamon 线程的停止动作还未完成,那么这个异常仍然会出现

天涯刀

2017-03-13 17:50

@JFinal 感谢您及时的回复。这这样几个问题需要说明下:
1.导致内存溢出的线程并不是我们自己创建的,它是druid线程池内的线程。我尝试在项目完成启动之后,将对应的线程修改为deamon 线程,但是会报错。我的理解是正在运行的线程无法将其改为deamon 线程。
2.项目二导致溢出的线程和项目一的并不完全相同,可是使用的线程池,工程架构,以及jar包等都几乎是相同的。
3.这个内存溢出的问题,并不是绝对会出现的,有时候完全不做任何修改,仅仅重新打包就可以完好的运行。

另:附上个人实现的Tomcat关闭监听事件。
web.xml里面:

com.police.pro.job.JobListener


监听实现的方法:
package com.police.pro.job;

import java.util.Set;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;

public class JobListener implements ServletContextListener {

@Override
public void contextInitialized(ServletContextEvent sce) {
// TODO Auto-generated method stub

}

@Override
public void contextDestroyed(ServletContextEvent sce) {

try {
//将指定的线程关闭
Set threads=Thread.getAllStackTraces().keySet();
// File file=new File("E:/the.txt");
// if(!file.exists()){
// file.createNewFile();
// }
// BufferedWriter bw=new BufferedWriter(new FileWriter(file,true));
for (Thread thread : threads) {
//获取线程的名称
String threadName=thread.getName();
if(threadName!=null && threadName.contains("DefaultQuartzScheduler")){
thread.stop();

System.out.println("被主动关闭的线程名称:"+threadName);
//将该线程的名字写到一个文件中
//bw.write(threadName);
}
}
//bw.close();
Thread.sleep(1000*3);
} catch (Exception e) {
e.printStackTrace();
}
}
}

以上就是个人疑问。

JFinal

2017-03-13 19:34

druid 自身有类似于 shutdown 和 destroy 类的方法关闭线程,如果是用的 jfinal 提供的 DriudPlugin,如果通过 me.add(druidPlugin) 过的,jfinal 会自动关闭线程,无需干预

此外,上面的代码之中 thread.stop() 这样的代码并不可靠,这个在网上有很多相关资料,这个方法的不可靠性或许就是你所碰到的有时候出问题,有时候不出问题的根本原因

天涯刀

2017-03-16 16:15

@JFinal看来我需要重新找个思路去解决这个问题。非常感谢您的帮忙。另外我是您的粉丝,相信jfinal 也会越来越好!

热门反馈

扫码入社