Java 此代码中存在LDAP连接泄漏

Java 此代码中存在LDAP连接泄漏,java,ldap,resources,memory-leaks,Java,Ldap,Resources,Memory Leaks,有人能解释一下为什么这段代码会随机“泄漏”LDAP连接吗?我可以看到,随着时间的推移,已建立的TCP/IP连接的数量不断增加,在某个阶段,这开始导致问题。我试图摆弄com.sun.jndi.ldap.connect环境属性(启用池、禁用池等等),但似乎没有任何帮助 这意味着我那蹩脚的代码有错误。一般来说,如何做得更好并确保我从不“泄漏”LDAP连接 import java.util.ArrayList; import java.util.List; import java.util.Proper

有人能解释一下为什么这段代码会随机“泄漏”LDAP连接吗?我可以看到,随着时间的推移,已建立的TCP/IP连接的数量不断增加,在某个阶段,这开始导致问题。我试图摆弄com.sun.jndi.ldap.connect环境属性(启用池、禁用池等等),但似乎没有任何帮助

这意味着我那蹩脚的代码有错误。一般来说,如何做得更好并确保我从不“泄漏”LDAP连接

import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingEnumeration;
import javax.naming.NamingException;
import javax.naming.directory.Attributes;
import javax.naming.directory.InitialDirContext;
import javax.naming.directory.SearchControls;
import javax.naming.directory.SearchResult;

public class LdapUtil {
    private String ldap_context = "ou=myunit,dc=com";
    protected static String ldap_server = "ldap://ldapserver:389/";
    private String ldap_prefix = "(&(uid=";
    private String ldap_postfix = ")(objectclass=inetOrgPerson))";
    private String[] ldap_attributes = {"uid","departmentNumber","cn","postOfficeBox","mail"};
    private Properties ldap_properties;
    private SearchControls ldap_searchcontrols;
        private static String ldap_principal = "uid=bind_account,cn=users,ou=myunit,dc=com";
        private static String ldap_credentials = "qwerty";

    private List<String> getUserAttributes(final String userId) {
        List<String> UserAttributes = new ArrayList<String>();
        InitialDirContext ctx = null;
        NamingEnumeration<SearchResult> resultsEnum = null;
        NamingEnumeration<String> atrEnum = null;

        // Connect the LDAP
        try {
        ctx = new InitialDirContext(this.ldap_properties);
        // Prepare the query string
        String query = this.ldap_prefix+ userId+ this.ldap_postfix;
        // Query!
        resultsEnum = ctx.search(this.ldap_context, query, this.ldap_searchcontrols);

        // Enumerate the results
        while (resultsEnum.hasMore()) {
            SearchResult sr = (SearchResult) resultsEnum.nextElement();

            // Get all the attributes for a hit
            Attributes atr = sr.getAttributes();
            // Enumerate the attributes
            atrEnum = atr.getIDs();

            while (atrEnum.hasMore()) {
                    String nextid = atrEnum.nextElement();
                    String nextattribute = atr.get(nextid).toString();
                    UserAttributes.add(nextattribute);
            }

        }
        } catch ( Exception eom ) {
            System.out.println("LDAP exception");
        } finally {
            try {
                if (atrEnum!=null)
                atrEnum.close();
                if (resultsEnum!=null)
                resultsEnum.close();
                if (ctx!=null)
                ctx.close();
            } catch (NamingException eo) {
                // nothing
            } catch (NullPointerException eo) {
                // Nothing
            }
        } 
        return UserAttributes;
    }


    /*
     * Parses the LDAP search results and searches for selected attribute.
     */
    private String getAttribute (final List<String> attributes,final String attribuutti) {
        String result = null;
        // Let's go through all attributes
        for (int i = 0; i < attributes.size(); i++) {
            String attribute = attributes.get(i).toString();
            // Look for match
            if (attribute.startsWith(attribuutti)) {
                // Return the value after the space
                int k = attribute.indexOf(" ");
                result = attribute.substring(k+1,attribute.length());
            }
        }
        return result;
    }


    public LdapUtil(String remoteuser) {

        // Pre-initialize LDAP connection related properties
        this.ldap_properties = new Properties();
        this.ldap_properties.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
        this.ldap_properties.put(Context.PROVIDER_URL, ldap_server) ;
        this.ldap_properties.put(Context.REFERRAL, "follow" );
        this.ldap_properties.put(Context.SECURITY_AUTHENTICATION, "simple");
        this.ldap_properties.put(Context.SECURITY_PRINCIPAL,ldap_principal);
        this.ldap_properties.put(Context.SECURITY_CREDENTIALS,ldap_credentials);
        this.ldap_properties.put("com.sun.jndi.ldap.read.timeout", "10000");
        this.ldap_properties.put("com.sun.jndi.ldap.connect.timeout", "10000");
        // Tried with both pooling and without - doesn't solve problems
        this.ldap_properties.put("com.sun.jndi.ldap.connect.pool", "false");

        // Pre-initialize LDAP search controls
        this.ldap_searchcontrols = new SearchControls();
        this.ldap_searchcontrols.setSearchScope(SearchControls.SUBTREE_SCOPE);
        this.ldap_searchcontrols.setReturningAttributes(this.ldap_attributes);

            // The List for attributes
        List<String> attributes = null;

        attributes = getUserAttributes(remoteuser);
    }

}
import java.util.ArrayList;
导入java.util.List;
导入java.util.Properties;
导入javax.naming.Context;
导入javax.naming.InitialContext;
导入javax.naming.NamingEnumeration;
导入javax.naming.NamingException;
导入javax.naming.directory.Attributes;
导入javax.naming.directory.InitialDirContext;
导入javax.naming.directory.SearchControls;
导入javax.naming.directory.SearchResult;
公共类LdapUtil{
私有字符串ldap_context=“ou=myunit,dc=com”;
受保护的静态字符串ldap_服务器=”ldap://ldapserver:389/";
私有字符串ldap_prefix=“(&(uid=“;
私有字符串ldap_postfix=“)(objectclass=inetOrgPerson))”;
私有字符串[]ldap_属性={“uid”、“部门号”、“cn”、“邮局信箱”、“邮件”};
私人物业;私人物业;;
私有搜索控制ldap_搜索控制;
私有静态字符串ldap\u principal=“uid=bind\u account,cn=users,ou=myunit,dc=com”;
私有静态字符串ldap_credentials=“qwerty”;
私有列表getUserAttributes(最终字符串用户ID){
List UserAttributes=new ArrayList();
InitialDirContext ctx=null;
NamingEnumeration resultsEnum=null;
NamingEnumeration atrEnum=null;
//连接LDAP
试一试{
ctx=新的InitialDirContext(this.ldap_属性);
//准备查询字符串
字符串查询=this.ldap\u前缀+userId+this.ldap\u后缀;
//询问!
resultsum=ctx.search(this.ldap\u上下文、查询、this.ldap\u search控件);
//列举结果
while(resultnum.hasMore()){
SearchResult sr=(SearchResult)resultsum.nextElement();
//获取命中的所有属性
Attributes atr=sr.getAttributes();
//列举属性
atrEnum=atr.getIDs();
while(atrEnum.hasMore()){
字符串nextid=atrEnum.nextElement();
字符串nextattribute=atr.get(nextid.toString();
添加(nextattribute);
}
}
}捕获(异常eom){
System.out.println(“LDAP异常”);
}最后{
试一试{
如果(atrEnum!=null)
atrEnum.close();
如果(resultsum!=null)
resultnum.close();
如果(ctx!=null)
ctx.close();
}捕获(Naming异常eo){
//没什么
}捕获(NullPointerException eo){
//没什么
}
} 
返回用户属性;
}
/*
*解析LDAP搜索结果并搜索所选属性。
*/
私有字符串getAttribute(最终列表属性、最终字符串属性){
字符串结果=null;
//让我们检查所有属性
对于(int i=0;i
atrEnum.close()
异常失败时,
resultnum
ctx
永远不会关闭

要解决这个问题,只需将所有
close()
调用都放在自己的try/catch块中

} finally {
    if (atrEnum != null) try { 
        atrEnum.close(); 
    } catch (NamingException logOrIgnore) {}
    if (resultsEnum != null) try {
        resultsEnum.close();
    } catch (NamingException logOrIgnore) {}
    if (ctx != null) try {
        ctx.close();
    } catch (NamingException logOrIgnore) {}
}

一个明显的问题是您的
finally
块是错误的。Ff
close
抛出异常,将不调用以下
close
方法。始终编写以下代码:

final Res res = acquire();
try {
    use(res);
} finally {
    res.release();
}
即使这意味着筑巢,最后也要尝试


(如果您使用的是旧版本的Sun JRE,则在异常情况下会出现LDAP(和Kerberos)资源泄漏问题。)

谢谢您的回答。我写道:

private void closeResources(final InitialDirContext ctx,final NamingEnumeration<SearchResult> resultsEnum,final NamingEnumeration<String> atrEnum) {
    try {
        atrEnum.close();
    } catch (Exception eom) {}

    try {
        resultsEnum.close();
    } catch (Exception eom) {}

    try {
        ctx.close();
    } catch (Exception eom) {}
}
private void closeResources(final InitialDirContext ctx、final namingumeration resultnum、final namingumeration atrEnum)
private void closeResources(final InitialDirContext ctx,final NamingEnumeration<SearchResult> resultsEnum,final NamingEnumeration<String> atrEnum) {
    try {
        atrEnum.close();
    } catch (Exception eom) {}

    try {
        resultsEnum.close();
    } catch (Exception eom) {}

    try {
        ctx.close();
    } catch (Exception eom) {}
}