我们使用Apache Avro作为我们的Python应用程序和我们在Tomcat服务中运行的一些第三方Java库之间的JSON接口。我们决定简单地扩展org.apache.avro.ipc.ResponderServlet类来实现我们自己的servlet。 servlet非常简单,它在构造函数中实例化ResponderServlet超类,并覆盖init()和destroy()方法,为我们在servlet中运行的第三方库做一些内容管理。
但是当Tomcat取消部署我们的webapp时,我们会看到一些与ThreadLocal相关的内存泄漏的SEVERE错误警告。
SEVERE: The web application [/hotwire] created a ThreadLocal with key of type [org.apache.avro.Schema$3] (value [org.apache.avro.Schema$3@4464784f]) and a value of type [java.lang.Boolean] (value [true]) 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.
Jan 24, 2013 2:19:36 AM org.apache.catalina.loader.WebappClassLoader checkThreadLocalMapForLeaks
SEVERE: The web application [/hotwire] created a ThreadLocal with key of type [org.apache.avro.generic.GenericDatumReader$1] (value [org.apache.avro.generic.GenericDatumReader$1@2016ad9d]) and a value of type [org.apache.avro.util.WeakIdentityHashMap] (value [org.apache.avro.util.WeakIdentityHashMap@30e02ee0]) 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.
我们可能在某处做了一些天真的事情,因为我们无法在网络上的任何地方找到任何帮助。尽管如此,我们希望有人能告诉我们哪里出错了。
以下是我们的servlet的一瞥。
public class HotWire extends ResponderServlet{
public HotWire() throws IOException
{
super(new SpecificResponder(Engine.class, new EngineImpl()));
}
@Override
public void init() {
try {
super.init();
try {
init_engine();
} catch (EngineInitException e) {
e.printStackTrace();
}
} catch (ServletException e) {
e.printStackTrace();
}
}
@Override
public void destroy() {
super.destroy();
shutdown_engine();
}
public static class EngineImpl implements EngineInterface {
public Boolean create(Parameters message) {
Boolean status = null;
try {
status = engine.create_object(message);
} catch (SemanticException | IOException e) {
e.printStackTrace();
}
return status;
}
}
答案 0 :(得分:0)
我看到了类似的问题。如果您在此处查看,则有一个静态ThreadLocal缓存已被填充,无法删除它:
private static final ThreadLocal<Map<Schema, Map<Schema, ResolvingDecoder>>> RESOLVER_CACHE = ThreadLocal
.withInitial(WeakIdentityHashMap::new);
对于我来说,每个请求都具有不同的架构,因此我的Spring Boot服务最终会耗尽内存并死亡。
这也是类加载器泄漏的示例: ThreadLocal & Memory Leak
我可以在此处看到JIRA要求进行的改进: https://issues.apache.org/jira/browse/AVRO-1595
更新:我能够解决内存泄漏问题。有一个ExecutorService正在重用线程。现在,我关闭了导致线程完成的服务。这样就可以对ThreadLocal内存进行GC处理。
正如某人指出的那样,RESOLVER_CACHE使用了WeakIdentityHashMap,该映射应允许对GC进行缓存,但这对我而言并非如此。