我正在Scala中开发一个基于Servlet的Web应用程序,并使用Akka。在启动和运行时一切正常,我在查看代码时看到没有错误,我的孩子们都把自己搞砸了,正确关闭了自己。然而;当我尝试关闭服务器或重新部署时,我在控制台中遇到了很多错误:
Shutting down...
Shut down successfully.
27-Mar-2015 11:21:22.233 SEVERE [localhost-startStop-2] org.apache.catalina.loader.WebappClassLoaderBase.checkThreadLocalMapForLeaks The web application [ROOT] created a ThreadLocal with key of type [java.lang.ThreadLocal] (value [java.lang.ThreadLocal@68d6d1aa]) and a value of type [scala.concurrent.forkjoin.ForkJoinPool.Submitter] (value [scala.concurrent.forkjoin.ForkJoinPool$Submitter@1045f98]) but failed to remove it when the web application was stopped. Threads are going to be renewed over time to try and avoid a probable memory leak.
27-Mar-2015 11:21:22.233 SEVERE [localhost-startStop-2] org.apache.catalina.loader.WebappClassLoaderBase.checkThreadLocalMapForLeaks The web application [ROOT] created a ThreadLocal with key of type [scala.util.DynamicVariable$$anon$1] (value [scala.util.DynamicVariable$$anon$1@5f818593]) and a value of type [org.apache.tomcat.util.log.SystemLogHandler] (value [org.apache.tomcat.util.log.SystemLogHandler@5b616a23]) but failed to remove it when the web application was stopped. Threads are going to be renewed over time to try and avoid a probable memory leak.
27-Mar-2015 11:21:22.241 INFO [main] org.apache.coyote.AbstractProtocol.stop Stopping ProtocolHandler ["http-nio-8080"]
27-Mar-2015 11:21:22.243 INFO [main] org.apache.coyote.AbstractProtocol.stop Stopping ProtocolHandler ["ajp-nio-8009"]
27-Mar-2015 11:21:22.244 INFO [main] org.apache.coyote.AbstractProtocol.destroy Destroying ProtocolHandler ["http-nio-8080"]
27-Mar-2015 11:21:22.244 INFO [main] org.apache.coyote.AbstractProtocol.destroy Destroying ProtocolHandler ["ajp-nio-8009"]
Disconnected from server
如果我尝试使用常规的同步servlet,我在关机时不会在日志中收到消息。
我在servlet上有一个上下文监听器,它是:
class ContextListener extends ServletContextListener {
private var system: ActorSystem = _
override def contextInitialized(sce: ServletContextEvent): Unit = {
val context = sce.getServletContext
system = ActorSystem.create("StridentStandard")
context.setAttribute("actor.system", system)
}
override def contextDestroyed(sce: ServletContextEvent): Unit = {
println("Shutting down...")
system.shutdown()
system.awaitTermination()
println("Shut down successfully.")
}
}
所以,从它看起来的样子 - ActorSystem 应该正确关闭 - 但似乎有些线程挂在上面。
我对Scala和Akka以及并发都很新,因此我不确定从这里开始。
答案 0 :(得分:1)
答案 1 :(得分:1)
问题的关键在于此日志行
27-Mar-2015 11:21:22.233 SEVERE [localhost-startStop-2] org.apache.catalina.loader.WebappClassLoaderBase.checkThreadLocalMapForLeaks The web application [ROOT] created a ThreadLocal with key of type [scala.util.DynamicVariable$$anon$1] (value [scala.util.DynamicVariable$$anon$1@5f818593]) and a value of type [org.apache.tomcat.util.log.SystemLogHandler] (value [org.apache.tomcat.util.log.SystemLogHandler@5b616a23]) but failed to remove it when the web application was stopped. Threads are going to be renewed over time to try and avoid a probable memory leak.
在webapp卸载时,Tomcat收到了很多资源泄漏的报告,这些报告是由于webapp而不是他们实现此检查的tomcat容器造成的。错误不是报告akka线程已经运行,而是存储在ThreadLocal中的值尚未清除。这将阻止JVM在卸载webapp时对Web应用程序进行GC操作。
罪魁祸首是DynamicVariable,一个包装ThreadLocal的scala类。要删除此错误,您需要跟踪谁正在使用此代码并使其自行清理。如果是负责的akka代码,那么尝试升级到更高版本,如果问题仍然存在,请考虑向akka团队提交补丁。
Tomcat记录了他们的内存泄漏保护协议here。