Linux Tomcat 不会停止。我该如何调试?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/9971876/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Tomcat doesn't stop. How can I debug this?
提问by Jim
I have a Tomcat 7
running in Linux that I start via $CATALINA_HOME/bin/startup.sh
and shutdown via $CATALINA_HOME/bin/shutdown.sh
from /etc/init.d
我Tomcat 7
在 Linux 中运行,我$CATALINA_HOME/bin/startup.sh
通过$CATALINA_HOME/bin/shutdown.sh
从启动和关闭/etc/init.d
All is ok except 1 problem. Sometimes tomcat does not stop.
Although I stop it and I see in catalina.out logs that is going down, if I do ps -ef
I can still see the process running.
除了 1 个问题,一切正常。有时tomcat不会停止。
虽然我停止了它并且我在 catalina.out 日志中看到正在下降,但如果我这样做,ps -ef
我仍然可以看到进程正在运行。
What could be the problem? How can I debug this? My feeling is, that this is related to threads.
可能是什么问题呢?我该如何调试?我的感觉是,这与线程有关。
So the parts that are suspicious are the following:
1) I use Log4j's LogManager to detect if the log4j configuration has been changed, but I do Log4jManager.shutdown
on a contextDestroyed
ServletContextListener
2) I use H2
database and I see on shutdown:
因此,可疑的部分如下:
1)我使用 Log4j 的 LogManager 来检测 log4j 配置是否已更改,但我Log4jManager.shutdown
在contextDestroyed
ServletContextListener
2)我使用H2
数据库并在关闭时看到:
SEVERE: The web application [/MyApplication] appears to have started a
thread named [H2 Log Writer MYAPPLICATION] but has failed to stop it.
This is very likely to create a memory leakSEVERE: The web application [/MyApplication] appears to have started a
thread named [H2 File Lock Watchdog
/opt/myOrg/tomcat/webapps/MyApplication/db/myDatabase.lock.db] but has
failed to stop it. This is very likely to create a memory leak. Apr 2,
2012 9:08:08 AM org.apache.catalina.loader.WebappClassLoader
clearReferencesThreads SEVERE: The web application [/MyApplication]
appears to have started a thread named [FileWatchdog] but has failed
to stop it. This is very likely to create a memory leak.
严重:Web 应用程序 [/MyApplication] 似乎已启动
名为 [H2 Log Writer MYAPPLICATION]的线程,但未能将其停止。
这很可能造成内存泄漏严重:Web 应用程序 [/MyApplication] 似乎启动了一个
名为 [H2 File Lock Watchdog
/opt/myOrg/tomcat/webapps/MyApplication/db/myDatabase.lock.db]的线程,但
未能阻止它。这很可能造成内存泄漏。
2012 年4 月 2日上午 9:08:08 org.apache.catalina.loader.WebappClassLoader
clearReferencesThreads 严重:Web 应用程序 [/MyApplication]
似乎启动了一个名为 [FileWatchdog] 的线程,但未能
阻止它。这很可能造成内存泄漏。
Any help please? How can I detect the problem here?
请问有什么帮助吗?我怎样才能发现这里的问题?
UPDATE:
I did a kill -3
as suggested by @daveb, and in the catalina.out I see:
更新:
我kill -3
按照@daveb 的建议做了一个,在 catalina.out 中我看到:
JVMDUMP006I Processing dump event "user", detail "" - please wait. JVMDUMP032I JVM requested Java dump using '/etc/init.d/javacore.20120402.093922.2568.0001.txt' in response to an event JVMDUMP010I Java dump written to /etc/init.d/javacore.20120402.093922.2568.0001.txt JVMDUMP013I Processed dump event "user", detail "".
JVMDUMP006I 正在处理转储事件“user”,详细信息“”- 请稍候。JVMDUMP032I JVM 使用“/etc/init.d/javacore.20120402.093922.2568.0001.txt”请求 Java 转储,以响应事件 JVMDUMP010I Java 转储写入 /etc/init.d/javacore.20120402.0950601.txt “用户”,详细信息“”。
There is a javacore in /etc/init.d
but I don't know how to process it. I.e. what parts should I investigate
有一个javacore,/etc/init.d
但我不知道如何处理它。即我应该调查哪些部分
采纳答案by Thomas Mueller
If the web application is stopped, all connections to the database should be closed as well. If you don't have a list of connections, then execute the SQL statement "shutdown" (this only works for the H2 and HSQLDB databases).
如果 Web 应用程序停止,则与数据库的所有连接也应关闭。如果您没有连接列表,则执行 SQL 语句“shutdown”(这只适用于 H2 和 HSQLDB 数据库)。
If you have a registered a Servlet, you can do that in the Servlet.destroy()
method.
如果你有一个注册的 Servlet,你可以在Servlet.destroy()
方法中做到这一点。
If you have registered a ServletContextListener
, you can execute the "shutdown" statement in the ServletContextListener.contextDestroyed(ServletContextEvent servletContextEvent)
method. This is what org.h2.server.web.DbStarter
ServletContextListener
does (the one that is included in the H2 database).
如果你已经注册了一个ServletContextListener
,你可以在ServletContextListener.contextDestroyed(ServletContextEvent servletContextEvent)
方法中执行“shutdown”语句。这就是org.h2.server.web.DbStarter
ServletContextListener
(包含在 H2 数据库中的那个)。
回答by daveb
Find out what threads are still running (or blocked, waiting to run) by using jstack or sending a signal to the process:
通过使用 jstack 或向进程发送信号,找出哪些线程仍在运行(或阻塞、等待运行):
kill -3 pid
When you know this, you can make whatever it was that started them hook into the shutdown notification to stop the threads. Or make those threads deamon threads.
当您知道这一点时,您可以将启动它们的任何内容挂钩到关闭通知中以停止线程。或者让这些线程成为守护线程。
See This tomcat shutdown questionfor more details on this.
有关更多详细信息,请参阅此 tomcat 关闭问题。
If you don't know where your threads were created, then consider adding names to them - executors can take thread factories, and you can use those factories to set the deamon status of a thread and also to name it - so your stack trace will be clearer.
如果你不知道你的线程是在哪里创建的,那么考虑给它们添加名称——执行器可以使用线程工厂,你可以使用这些工厂来设置线程的守护进程状态并命名它——这样你的堆栈跟踪就会更清楚。
回答by Utku ?zdemir
I had the exact same problem. Sometimes, the command ./shutdown.sh
does not stop the tomcat process, and its java
process stays in the running processes.
我有同样的问题。有时,该命令./shutdown.sh
并没有停止tomcat进程,它的java
进程一直停留在正在运行的进程中。
I had solved this problem using the Tomcat version in the Ubuntu's software repositories, by:
我已经使用 Ubuntu 软件库中的 Tomcat 版本解决了这个问题,方法是:
sudo apt-get install tomcat7
After installing it from package manager and configuring some settings, I did not have any problems on stopping/starting Tomcat. I used this command to stop, and it never failed:
从包管理器安装它并配置一些设置后,我在停止/启动 Tomcat 时没有任何问题。我用这个命令来停止,它从来没有失败过:
service tomcat7 stop
which is nearly the same as
这几乎与
/etc/init.d/tomcat7 stop
Using this command runs the code block from the init script, specifically, the codes from the file /etc/init.d/tomcat7
. So I looked into it to see what it does to always kill the tomcat process succesfully. Here is the code block that runs when you use service tomcat7 stop
command:
使用此命令运行 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
;;
The important part is this:
重要的部分是这样的:
start-stop-daemon --stop --pidfile "$CATALINA_PID" \
--user "$TOMCAT7_USER" \
--retry=TERM/20/KILL/5 >/dev/null
This means "retry stopping until the process is stopped. Here is the --retry command documentation from start-stop-daemonmanual:
这意味着“重试停止直到进程停止。这是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. ...
-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. ...
So, --retry=TERM/20/KILL/5
means "Send TERMsignal to the process, wait 20 seconds, if it's still running, send KILLsignal, wait 5 seconds, if it's still running, there is a problem.
所以,--retry=TERM/20/KILL/5
意思是“向进程发送TERM信号,等待 20 秒,如果它仍在运行,发送KILL信号,等待 5 秒,如果它仍在运行,则有问题。
This means you can configure the tomcat to run as a deamon and use a command like this, or write a script to do that kind of action to stop tomcat, or just use Ubuntu and get the tomcat from the package manager.
这意味着您可以将 tomcat 配置为作为守护进程运行并使用这样的命令,或者编写一个脚本来执行这种操作来停止 tomcat,或者只使用 Ubuntu 并从包管理器中获取 tomcat。
回答by Marco
Check if your Web Application has some Scheduler active, like Quartz.
检查您的 Web 应用程序是否有一些调度程序处于活动状态,例如 Quartz。
If you don't stop it, Web Application Thread never ending until you kill it
如果你不阻止它,Web 应用程序线程永远不会结束,直到你杀死它
回答by JohannSig
In my case I had one rogue JPA EntityManager that wasn't being properly closed after use. Fixed that, and now I can Clean-and-Build again without killing the damn Java process everytime :)
就我而言,我有一个流氓 JPA EntityManager 在使用后没有正确关闭。修复了这个问题,现在我可以再次清理和构建而无需每次都杀死该死的 Java 进程:)
回答by Denorm
I also had the same problem. There was a ThrottledThreadPoolExecutor in my application that wasn't getting shutdown. When I shut it down properly, tomcat would stop cleanly. In order to figure out the problem, I had to remove all the apps from my tomcat webapps
directory and then add them one by one and see which one was causing the problem
我也有同样的问题。我的应用程序中有一个 ThrottledThreadPoolExecutor 没有关闭。当我正确关闭它时,tomcat 会干净利落地停止。为了找出问题所在,我不得不从我的 tomcatwebapps
目录中删除所有应用程序,然后将它们一一添加,看看是哪个导致了问题
回答by ticktock
If you're using a Scheduler or some other entity in your web app, you need to shut it down. Typically you have to use a ServletContextListener to provide the hook to make your shutdown call. A shutdown hook won't work in this case because the JVM is not shutting down (yet). Believe me, I've tried. If your code is in agent code or something outside the container/webapp, then a shutdown hook SHOULD work, though often it's a hair pulling experience to figure out why it's STILL not working. Note, I'm bald.
如果您在 Web 应用程序中使用调度程序或其他一些实体,则需要将其关闭。通常,您必须使用 ServletContextListener 来提供挂钩以进行关闭调用。在这种情况下,关闭挂钩将不起作用,因为 JVM 尚未关闭(尚未关闭)。相信我,我已经试过了。如果您的代码在代理代码中或容器/webapp 之外的其他内容中,那么关闭挂钩应该可以工作,尽管通常需要费力地找出为什么它仍然无法正常工作。请注意,我是秃头。