首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何消除由休眠线程引起的tomcat内存泄漏日志条目

如何消除由休眠线程引起的tomcat内存泄漏日志条目
EN

Stack Overflow用户
提问于 2015-06-29 16:50:34
回答 2查看 1.7K关注 0票数 1

是否知道如何处理以下Tomcat日志条目:

代码语言:javascript
复制
SEVERE: The web application [/my-app] appears to have started a thread named [Thread-11] but has failed to stop it. This is very likely to create a memory leak.
Jun 29, 2015 11:14:33 AM org.apache.catalina.loader.WebappClassLoader clearReferencesThreads

我要在关闭tomcat 7.0.42的时候得到它们。

线程转储如下所示:

代码语言:javascript
复制
"Thread-11" daemon prio=10 tid=0x00007fedc0bd5000 nid=0x2983 waiting on condition [0x00007fedbacef000]
   java.lang.Thread.State: TIMED_WAITING (sleeping)
    at java.lang.Thread.sleep(Native Method)
    at com.my.app.Test$WorkerThread.run(Test.java:248)

其中java行248为:睡眠(1000*60*pollIntervalMinutes);

代码语言:javascript
复制
  public void start()
{

    WorkerThread t= new WorkerThread(this);
    t.setDaemon(true);
    t.start();
}
private class WorkerThread extends Thread
    {
        Controller controller=null;
        int pollIntervalMinutes=0;
        private boolean alive = true;

        public WorkerThread(Controller controller)
        {
            this.controller=controller;
            pollIntervalMinutes=60;
        }

        @Override
        public void run()
        {
            while(alive)
            {
                try
                {
                    sleep(1000*60*pollIntervalMinutes);
                    controller.createAllProjectsIfNeeded();
                }
                catch (Exception e)
                {
                    alive = false;
                }
            }
        }
    }

谢谢

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2015-06-29 17:47:53

问题似乎是Tomcat没有做任何尝试来阻止应用程序创建的非托管线程。

查找报告错误的org.apache.catalina.loader.WebappClassLoader clearReferencesThreads的实现,JVM线程将从清理过程中跳过。

因此,我要说的是,InterruptedException从未抛出,因此也不会像预期的那样,将活动设置为false。

代码语言:javascript
复制
 @SuppressWarnings("deprecation")
    private void clearReferencesThreads() {
        Thread[] threads = getThreads();

    // Iterate over the set of threads
    for (Thread thread : threads) {
        if (thread != null) {
            ClassLoader ccl = thread.getContextClassLoader();
            if (ccl == this) {
                // Don't warn about this thread
                if (thread == Thread.currentThread()) {
                    continue;
                }

                // JVM controlled threads
                ThreadGroup tg = thread.getThreadGroup();
                if (tg != null &&
                        JVM_THREAD_GROUP_NAMES.contains(tg.getName())) {

                    // HttpClient keep-alive threads
                    if (clearReferencesHttpClientKeepAliveThread &&
                            thread.getName().equals("Keep-Alive-Timer")) {
                        thread.setContextClassLoader(parent);
                        log.debug(sm.getString(
                                "webappClassLoader.checkThreadsHttpClient"));
                    }

                    // Don't warn about remaining JVM controlled threads
                    continue;
                }

                // Skip threads that have already died
                if (!thread.isAlive()) {
                    continue;
                }

                // TimerThread can be stopped safely so treat separately
                if (thread.getClass().getName().equals(
                        "java.util.TimerThread") &&
                        clearReferencesStopTimerThreads) {
                    clearReferencesStopTimerThread(thread);
                    continue;
                }

                if (isRequestThread(thread)) {
                    log.error(sm.getString("webappClassLoader.warnRequestThread",
                            contextName, thread.getName()));
                } else {
                    log.error(sm.getString("webappClassLoader.warnThread",
                            contextName, thread.getName()));
                }

                // Don't try an stop the threads unless explicitly
                // configured to do so
                if (!clearReferencesStopThreads) {
                    continue;
                }

                // If the thread has been started via an executor, try
                // shutting down the executor
                try {
                    Field targetField =
                        thread.getClass().getDeclaredField("target");
                    targetField.setAccessible(true);
                    Object target = targetField.get(thread);

                    if (target != null &&
                            target.getClass().getCanonicalName().equals(
                            "java.util.concurrent.ThreadPoolExecutor.Worker")) {
                        Field executorField =
                            target.getClass().getDeclaredField("this$0");
                        executorField.setAccessible(true);
                        Object executor = executorField.get(target);
                        if (executor instanceof ThreadPoolExecutor) {
                            ((ThreadPoolExecutor) executor).shutdownNow();
                        }
                    }
                } catch (SecurityException e) {
                    log.warn(sm.getString(
                            "webappClassLoader.stopThreadFail",
                            thread.getName(), contextName), e);
                } catch (NoSuchFieldException e) {
                    log.warn(sm.getString(
                            "webappClassLoader.stopThreadFail",
                            thread.getName(), contextName), e);
                } catch (IllegalArgumentException e) {
                    log.warn(sm.getString(
                            "webappClassLoader.stopThreadFail",
                            thread.getName(), contextName), e);
                } catch (IllegalAccessException e) {
                    log.warn(sm.getString(
                            "webappClassLoader.stopThreadFail",
                            thread.getName(), contextName), e);
                }

                // This method is deprecated and for good reason. This is
                // very risky code but is the only option at this point.
                // A *very* good reason for apps to do this clean-up
                // themselves.
                thread.stop();
            }
        }
    }
}

我可以想出三种方法来避免内存泄漏:

  • 提供关闭钩子作为一个线程,它知道您生成的线程,并可以中断它们。

如何添加关机挂钩

  • 不要生成线程,这些线程会在while循环中无休止地旋转,这样它们就可以在完成处理时停止。
  • 将线程包装在ExecutorService中,并在应用程序关闭事件时调用shutdownNow()。 这可以通过使用@WebListener注释的服务类来实现,并在方法:contextDestroyed(ServletContextEvent event)中调用shutdownNow()

shutdownNow()

尝试停止所有正在执行的任务,停止等待任务的处理,并返回等待执行的任务列表。此方法不等待主动执行任务终止。使用awaitTermination来完成这个任务。 除了尽力停止处理积极执行的任务之外,没有任何保证。例如,典型的实现将通过Thread.interrupt()取消,因此任何无法响应中断的任务都可能永远不会终止。

票数 2
EN

Stack Overflow用户

发布于 2015-06-29 20:06:41

我建议您在上下文中添加一个ServletContextListener (示例),它与线程通信,并在上下文被破坏时停止它。这样,当您的应用程序卸载(如果您删除或替换它),线程停止,并启动一个新的。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/31121241

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档