Tomcat不停止。 我怎样才能debugging呢?

我有一个运行在Linux中的Tomcat 7 ,通过$CATALINA_HOME/bin/startup.sh启动,并通过$CATALINA_HOME/bin/shutdown.sh
来自/etc/init.d

除了1个问题,一切都可以。 有时候tomcat不会停止。
虽然我停下来,我看到在catalina.out日志下降,如果我做ps -ef我仍然可以看到进程运行。

可能是什么问题呢? 我怎样才能debugging呢? 我的感觉是,这与线程有关。

所以可疑的部分如下:
1)我使用Log4j的LogManager来检测log4jconfiguration是否已经改变,但是我做Log4jManager.shutdowncontextDestroyed ServletContextListener
2)我使用H2数据库,我看到关机:

严重:Web应用程序[/ MyApplication]似乎已经开始了
线程命名为[H2 Log Writer MYAPPLICATION],但未能阻止它。
这很可能造成内存泄漏

严重:Web应用程序[/ MyApplication]似乎已经开始了
线程命名为[H2 File Lock Watchdog
/opt/myOrg/tomcat/webapps/MyApplication/db/myDatabase.lock.db],但已
未能阻止它。 这很可能造成内存泄漏。 Apr 2,
2012 9:08:08 org.apache.catalina.loader.WebappClassLoader
clearReferencesThreads SEVERE:Web应用程序[/ MyApplication]
似乎已经启动了一个名为[FileWatchdog]的线程,但失败了
停止它。 这很可能造成内存泄漏。

请帮忙吗? 我怎样才能在这里发现问题?

更新:
我按照@daveb的build议kill -3 ,在catalina.out中我看到:

JVMDUMP006I正在处理转储事件“user”,详细信息“” – 请稍候。 JVMDUMP032I JVM使用“/etc/init.d/javacore.20120402.093922.2568.0001.txt”请求Java转储以响应事件JVMDUMP010I写入到/etc/init.d/javacore.20120402.093922.2568.0001.txt的Java转储JVMDUMP013I处理的转储事件“用户”,详细信息“”。

/etc/init.d有一个javacore,但我不知道如何处理它。 即我应该调查哪些部分

如果Web应用程序停止,则所有与数据库的连接也应该关闭。 如果没有连接列表,则执行SQL语句“shutdown”(仅适用于H2和HSQLDB数据库)。

如果你已经注册了一个Servlet,你可以在Servlet.destroy()方法中做到这一点。

如果你已经注册了ServletContextlistner ,你可以在ServletContextlistner.contextDestroyed(ServletContextEvent servletContextEvent)方法中执行“shutdown”语句。 这是什么org.h2.server.web.DbStarter ServletContextlistner (包含在H2数据库中)。

通过使用jstack或向进程发送信号,找出哪些线程仍在运行(或阻塞,等待运行):

 kill -3 pid 

当你知道这一点的时候,你可以使任何启动它们的钩子进入关闭通知来停止线程。 或者让那些线程deamon线程。

看到这个关于这个tomcat关机问题的更多细节。

如果你不知道你的线程是在哪里创建的,那么考虑给它们添加名字 – 执行者可以使用线程工厂,并且可以使用这些工厂来设置线程的deamon状态并命名它 – 这样你的堆栈跟踪将会更清楚。

检查您的Web应用程序是否有一些调度程序处于活动状态,如Quartz。

如果你不停止它,Web应用程序线程永远不会结束,直到你杀死它

我有同样的问题。 有时,命令./shutdown.sh不会停止tomcat进程,并且其java进程停留在正在运行的进程中。

我已经使用Ubuntu软件仓库中的Tomcat版本解决了这个问题,方法是:

 sudo apt-get install tomcat7 

在从软件包管理器安装并配置一些设置后,我没有任何停止/启动Tomcat的问题。 我用这个命令停下来,它从来没有失败:

 service tomcat7 stop 

这几乎是一样的

 /etc/init.d/tomcat7 stop 

使用此命令将从init脚本运行代码块,具体来说是从/etc/init.d/tomcat7文件中的代码。 所以我研究了一下,看看它总是杀死tomcat进程成功。 以下是使用service tomcat7 stop命令时运行的代码块:

 log_daemon_msg "Stopping $DESC" "$NAME" set +e if [ -f "$CATALINA_PID" ]; then start-stop-daemon --stop --pidfile "$CATALINA_PID" \ --user "$TOMCAT7_USER" \ --retry=TERM/20/KILL/5 >/dev/null if [ $? -eq 1 ]; then log_progress_msg "$DESC is not running but pid file exists, cleaning up" elif [ $? -eq 3 ]; then PID="`cat $CATALINA_PID`" log_failure_msg "Failed to stop $NAME (pid $PID)" exit 1 fi rm -f "$CATALINA_PID" rm -rf "$JVM_TMP" else log_progress_msg "(not running)" fi log_end_msg 0 set -e ;; 

重要的是这样的:

 start-stop-daemon --stop --pidfile "$CATALINA_PID" \ --user "$TOMCAT7_USER" \ --retry=TERM/20/KILL/5 >/dev/null 

这意味着“重试停止,直到进程停止。以下是来自start-stop-daemon手册的–retry命令文档:

  -R|--retry timeout|schedule With --stop, specifies that start-stop-daemon is to check whether the process(es) do finish. It will check repeatedly whether any matching processes are running, until none are. If the processes do not exit it will then take further action as determined by the schedule. If timeout is specified instead of schedule then the schedule signal/timeout/KILL/timeout is used, where signal is the signal specified with --signal. ... 

所以,– --retry=TERM/20/KILL/5意思是“发送TERM信号给进程,等待20秒,如果还在运行,发送KILL信号,等待5秒钟,如果还在运行,就有问题。

这意味着你可以配置tomcat作为deamon运行并使用这样的命令,或者编写一个脚本来执行这种动作来阻止tomcat,或者使用Ubuntu并从包管理器中获取tomcat。

在我的情况下,我有一个流氓JPA EntityManager使用后没有正确关闭。 修正了,现在我可以再次清理和生成,而不必每次都杀死该死的Java进程:)

我也有同样的问题。 我的应用程序中没有关机的ThrottledThreadPoolExecutor。 当我把它关好的时候,tomcat会干净地停下来。 为了弄清楚这个问题,我不得不从我的tomcat webapps目录中删除所有的应用程序,然后逐个添加它们,看看是哪一个导致了问题

如果您在您的Web应用程序中使用调度程序或其他实体,则需要将其关闭。 通常,您必须使用ServletContextlistner来提供关闭呼叫的挂钩。 在这种情况下,关闭挂钩将不起作用,因为JVM尚未关闭(尚)。 相信我,我已经试过了。 如果你的代码是在代理代码中,或者在容器/ web应用程序之外,那么关闭钩子应该可以工作,尽管经常要弄清楚为什么它仍然不起作用。 请注意,我是秃头的。