2012-04-02 67 views
31

我有一个Tomcat 7在Linux上运行,我通过$CATALINA_HOME/bin/shutdown.sh
通过$CATALINA_HOME/bin/startup.sh和关机开始从/etc/init.dTomcat不停止。我怎样才能调试呢?

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

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

让可疑的部分如下:
1)我用Log4j的日志管理,以检测是否log4j的配置已经改变,但我Log4jManager.shutdown上一个contextDestroyedServletContextListener
2)我用H2数据库和我看到关机:

重度:Web应用程序[/为MyApplication]似乎已经启动名为[H2日志写入所有MyApplication]一个
线程,但未能阻止它。
这很可能造成泄漏

严重记忆:Web应用程序[/为MyApplication]似乎已经开始了
线程名为[H2文件锁定看门狗
的/ opt/MYORG/tomcat的/ webapps /下所有MyApplication /db/myDatabase.lock.db]但有
无法停止它。这很可能造成内存泄漏。 4月2日,
2012上午09时08分08秒org.apache.catalina.loader.WebappClassLoader
clearReferencesThreads重度:Web应用程序[/为MyApplication]
似乎已经开始了一个名为[FileWatchdog]线程,但未能
停止它。这很可能造成内存泄漏。

请帮忙吗?我如何在这里检测到问题?

UPDATE:
我做了kill -3通过@daveb的建议,并在catalina.out的我看到:

JVMDUMP006I处理倾倒事件 “用户”,细节 “” - 请稍候。 JVMDUMP032I JVM使用要求 “/etc/init.d/javacore.20120402.093922.2568.0001.txt” Java转储响应写入 /etc/init.d/javacore.20120402.093922.2568.0001.txt的 事件JVMDUMP010I Java转储JVMDUMP013I 已处理的转储事件“user”,详细信息“”。

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

+0

尝试将您的线程标记为守护线程,以便虚拟机不会等待它们死亡。 http://docs.oracle.com/javase/6/docs/api/java/lang/Thread.html#setDaemon(boolean)但是,当然这只对你自己的线程有用,而不是H2 – luukes 2012-04-02 06:53:53

+0

H2开始的创建守护线程。 – 2012-04-02 09:54:19

+0

@ThomasMueller:那么'SEVERE:Web应用程序[/ MYAPPLICATION]看起来是否启动了一个名为[H2 File Lock Watchdog /opt/myOrg/tomcat/webapps/MyApplication/lock.db]的线程,但未能停止它。这很可能会造成内存泄漏.'意味着在catalina.out?我没有创建这个,但是'H2'。 – Jim 2012-04-02 11:09:54

回答

4

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

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

如果您注册了ServletContextListener,则可以执行ServletContextListener.contextDestroyed(ServletContextEvent servletContextEvent)方法中的“关闭”语句。这就是org.h2.server.web.DbStarterServletContextListener所做的(包含在H2数据库中的)。

+0

感谢您的回复!'如果Web应用程序停止,所有与数据库的连接也应该关闭。我正在使用Tomcat的连接池。所以它已经不在我的手中了。这是Tomcat和H2之间的一个众所周知的'赛跑'问题。我可以做'SHUTDOWN'(它安全吗?),但我想确保我正确解决这个问题 – Jim 2012-04-02 12:55:46

+0

它看到了问题。不知道最好的解决方案是什么...忽略异常? “SHUTDOWN”语句只会关闭这个数据库,所以应该相对保存 - 只有当您不确定其他Web应用程序是否正在使用该数据库时,才会这样做。另一种解决方案是使用服务器模式(在另一个进程中运行H2数据库)。 – 2012-04-02 13:40:06

+0

:没有数据库是我的,即没有其他应用程序将访问它。而我需要在文件模式下使用它。所以基本上你是说1)关机对于数据是安全的2)我可以忽略这个异常,意思是什么?由于H2还在运行,Tomcat不会在关机时挂起?我在我的应用程序目录中看到'db.lock'文件 – Jim 2012-04-02 13:49:34

19

找出什么的线程仍在运行(或阻塞,等待运行)通过使用jstack或将信号发送到进程:

kill -3 pid 

当你知道这一点,你可以无论是开始他们挂钩到关闭通知停止线程。或者让这些线程deamon线程。

有关详细信息,请参见This tomcat shutdown question

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

+0

+1。请参阅OP – Jim 2012-04-02 07:03:21

+0

中的更新在文本编辑器中打开javacore .txt文件,查找包含您编写的软件包的线程堆栈。 – daveb 2012-04-02 07:09:44

+0

是的,我想通了,但我不知道什么表明一个错误。 – Jim 2012-04-02 07:16:02

6

我有完全相同的问题。有时候,命令./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 

这意味着“直到进程停止重试停止。下面是从起止守护手册--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。

7

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

如果你不阻止它,Web应用程序线程上房,直到你杀了它

1

在我来说,我有一个流氓的JPA EntityManager,这是使用后没有被正确关闭。修正了,现在我可以再次清理并重新构建,而不必每次都杀死该死的Java进程:)

0

我也有同样的问题。我的应用程序中没有关机的ThrottledThreadPoolExecutor。当我正确关闭它时,tomcat会干净地停下来。为了找出问题,我必须从我的tomcat webapps目录中删除所有应用程序,然后逐个添加它们,并查看哪一个导致了问题

0

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