2

问题:
使用 WAR 文件(在 WEB-INF/classes 中)部署 XCC 库会禁止在不重新启动整个 Tomcat 容器的情况下重新部署/更新该 web 应用程序。它只是停止工作,因为仍然分配了资源,因此 Tomcat 无法删除一些 JAR 文件。
在 Tomcat 的 lib 目录中部署库时(作为 JDBC 驱动程序),Tomcat 在 Tomcat 日志中写入内存泄漏警告,如下所示:

17-Mar-2016 10:58:45.683 WARNING [ContainerBackgroundProcessor[StandardEngine[Catalina]]] org.apache.catalina.loader.WebappClassLoaderBase.clearReferencesThreads The web application [api] appears to have started a thread named [Thread-4] but has failed to stop it. This is very likely to create a memory leak. Stack trace of thread:  java.lang.Thread.sleep(Native Method)  com.marklogic.xcc.ContentSourceFactory$ConnectionCollector.run(ContentSourceFactory.java:449)

我发现了什么:
我做了一些调查,发现(至少在 XCC 8.0.3 中)在 ContentSourceFactory 中启动了一个从未关闭的线程。该线程正在影响 servlet 的更新/重新部署并造成内存泄漏。我的快速解决方案是创建一个自定义 ContentSourceFactory,它有一个在 servlet 停止时调用的关闭方法。

问题:
不幸的是,我在文档中没有找到任何线索。那么在 servlet 容器中使用 XCC 库(8.x)的官方方法是什么?

4

2 回答 2

2

该线程似乎确实在 JVM 期间运行。我将为此打开一个缺陷。

基于在 tomcat 中使用不同产品的类似问题的经验的解决方法。DB 驱动器(尤其是 JDBC)历来以这种方式存在问题。

将 xcc.jar 放入 tomcat 的“共享库”类路径而不是 WAR 中。通常不建议这样做——但 OTOH 这正是存在共享库类路径的原因——这允许重新部署您的应用程序。只要您自己不共享活动连接对象,XCC 代码就是线程安全且与上下文无关的,它应该可以正常工作。

还要确保你勤奋地关闭或关闭所有响应对象,终结器可能需要很长时间才能启动。

-大卫

于 2016-03-17T18:04:23.590 回答
0

我的临时解决方案:
正如 DALDEI 提到的,它看起来像是 XCC 库中的一个未解决问题。DisposableContentSourceFactory为了做一个临时的解决方法,我根据原始来源(8.0.4)编写了一个。代码可以在这里找到:https ://gist.github.com/Mario-Eis/a16437c35d2aa097f668

这种方法还有一个优势,因为它可以平滑地集成到 IoC 上下文中,例如 Spring IoC。

@Configuration
public class XccContext {

    @Bean(destroyMethod = "shutdown")
    public DisposableContentSourceFactory contentSourceFactory() {
        return DisposableContentSourceFactory.create();
    }

    @Bean
    public ContentSource contentSource(XccConfiguration xccConfiguration, DisposableContentSourceFactory contentSourceFactory) throws XccConfigException {
        return contentSourceFactory.newContentSource(xccConfiguration.connectionString());
    }

    @Bean(destroyMethod = "close")
    @Scope(value = "request", proxyMode = ScopedProxyMode.INTERFACES)
    public Session marklogicSession(ContentSource contentSource) {
        return contentSource.newSession();
    }
}

为了保证对官方静态类方法的一点“兼容性”,我还包括了一个静态工厂方法create()

如果有公共 GIT 存储库,我可以提交拉取请求。

于 2016-03-18T08:47:27.817 回答