【问题标题】:LDAP Connections are not closed when using LdapTemplate使用 LdapTemplate 时未关闭 LDAP 连接
【发布时间】:2016-11-20 17:19:13
【问题描述】:

关闭 Tomcat 后,我​​们看到很多关于内存泄漏的错误,因为 Tomcat 未能停止线程。 根据 Tomcat,我们有大约 2600 个守护线程在 com.sun.jndi.ldap.Connection.pauseReader 中等待。

我们正在使用 LdapTemplate 从 LDAP 读取数据。每次我们需要从 LDAP 读取数据时都会创建 LdapTemplate。从文档中我看到所有资源都是在搜索结束后由 LdapTemplate 释放的。 我们没有为 LdapTemplate 启用池化,默认为 false。

经过调试发现,为Connection创建的线程并没有在搜索结束后立即被销毁,但一些线程最终被销毁了。

知道为什么会有这么多守护线程等待 com.sun.jndi.ldap.Connection.pauseReader 吗?

我们正在使用 spring-ldap 2.0.2.RELEASE。

关于我们如何在执行搜索之前创建 LdapTemplate 的示例代码:

LdapContextSource contextSource = new LdapContextSource();
SimpleAuthenticationSource authenticationSource = new SimpleAuthenticationSource(userDn, password);
contextSource.setAuthenticationSource(authenticationSource);
LdapTemplate ldapTemplate = new LdapTemplate(contextSource);
ldapTemplate.setIgnorePartialResultException(true);

更新: 设置池化为 true 后,连接释放正常。

ldapContextSource.setPooled(true); 

问题是我们不能使用池化。我仍然不明白为什么不使用池时连接没有正确释放。

【问题讨论】:

  • 你能举个例子说明你是如何使用 LdapTemplate 的,Spring 版本之类的东西,它会有所帮助

标签: java jndi spring-ldap


【解决方案1】:

您提到您没有使用连接池,但这可以很好地解决您遇到的线程失控问题。

Take a look here 了解如何使用 PoolingContextSource 通过 Spring XML 配置配置 LDAP 连接池。 Here is another example 如何使用基于注解的配置启用连接池。

注意文档中特别提到在 Spring LDAP 中启用池,而不是通过 "com.sun.jndi.ldap.connect.pool" 属性在 JDK 中启用 JNDI LDAP 提供程序。

作为参考,这里有一个 2013 年的类似问题,似乎启用连接池能够减少线程数:https://github.com/spring-projects/spring-security/issues/2397

【讨论】:

  • 不幸的是,我们不能使用池,因为每次凭据可能不同,因此无法重用连接。此外,我们使用 GSSAPI 进行身份验证和 TLS,因此根据文档连接池将无法正常工作。我从 2013 年就看到了这个问题,但我不确定我理解为什么 pool 有帮助。 LdapTemplate 不应该在搜索后关闭包括 Connection 在内的所有资源吗?
【解决方案2】:

经过大量调试后,问题是在其中一个查询中我们检索了上下文而没有关闭它:

ldapTemplate.getContextSource().getReadOnlyContext().getNameInNamespace()

而且我们没有在使用后关闭上下文。

关闭上下文解决了问题,修复后没有线程处于等待状态。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-10-21
    • 2010-09-11
    • 1970-01-01
    • 2014-08-17
    相关资源
    最近更新 更多