简体   繁体   中英

Dispose not working as expected in DirectorySearcher

I am trying to connect and do simple functionalities such as search on an Active Directory using C#. However, I am stuck in a problem. I am using DirectorySearcher to search the directory. There are loads of entries in the directory.

This is the function

void RunThis()
{
        DirectoryEntry de = new DirectoryEntry();
        de.Path = "LDAP://" + domainName;
        de.Username = username;
        de.Password = password;
        de.AuthenticationType = AuthenticationTypes.Secure;

        DirectorySearcher deSearch = new DirectorySearcher(de);
        //Skipping properties to load
        try
        {
            deSearch.SearchScope = SearchScope.Subtree;
            SearchResultCollection rescoll = deSearch.FindAll();
            deSearch.Dispose();
            rescoll.Dispose();
        }
        catch (Exception obj)
        {
            System.Console.WriteLine("Exception in getting results. {0}",obj.Message);
        }

     }
     de.Dispose();

} // end of function 

This is a sample function I trimmed down to. I could find a lot of posts which said that calling dispose explicitly of the DirectorySearcher or ResultCollection object will solve the problem.

However, I see that the memory used by the task is increasing constantly. There isnt much else going in the other part of the code. When i comment the function, the memory usage becomes stable.

Has anyone else faced the issue and found a solution?

PS: And there is no way out. I need to do the findall :(

You aren't disposing everything if an exception is thrown: you need to use a try/finally block or the equivalent using statement, something like:

void RunThis()
{
    using (DirectoryEntry de = new DirectoryEntry())
    {
        de.Path = "LDAP://" + domainName;
        de.Username = username;
        de.Password = password;
        de.AuthenticationType = AuthenticationTypes.Secure;

        using (DirectorySearcher deSearch = new DirectorySearcher(de))
        {
            deSearch.SearchScope = SearchScope.Subtree;
            using (SearchResultCollection rescoll = deSearch.FindAll())
            {
            }
        }
    }

} // end of function 

The solution is here

Memory Leak when using DirectorySearcher.FindAll()

Some problem with the FindAll API implementation. If you dont enumerate the results and not use it once, then dispose wont work properly. However, after enumerating it and a simple enumerator.moveNext() done once, it disposes nice and clean. This has solved my problem.! :)

First, you need to figure out whether it is managed or unmanaged memory that is leaking.

  1. Use perfmon to see what happens to your process '.net memory# Bytes in all Heaps' and Process\\Private Bytes. Compare the numbers and the memory rises. If the rise in Private bytes outpaces the rise in heap memory, then it's unmanaged memory growth.

  2. Unmanaged memory growth would point to objects that are not being disposed (but eventually collected when their finalizer executes).

  3. If it's managed memory growth, then we'll need to see which generation/LOH (there are also performance counters for each generation of heap bytes).

  4. If it's Large Object Heap bytes, you'll want to reconsider the use and throwing away of large byte arrays. Perhaps the byte arrays can be re-used instead of discarded. Also, consider allocating large byte arrays that are powers of 2. This way, when disposed, you'll leave a large "hole" in the large object heap that can be filled by another object of the same size.

  5. A final concern is pinned memory, but I don't have any advice for you on this because I haven't ever messed with it.

DirectoryEntry and DirectorySearcher both implement IDisposable . Also, you need to insure that they are disposed even in the event of an exception. I would suggest placing the construction of both inside using blocks .

EDIT: As does SearchResultCollection, so +1 to @Joe.

Try using a using statement instead

void RunThis()
{
        using(DirectoryEntry de = new DirectoryEntry())
        {
          de.Path = "LDAP://" + domainName;
          de.Username = username;
          de.Password = password;
          de.AuthenticationType = AuthenticationTypes.Secure;

          DirectorySearcher deSearch = new DirectorySearcher(de);
          //Skipping properties to load
          try
          {
            deSearch.SearchScope = SearchScope.Subtree;
            SearchResultCollection rescoll = deSearch.FindAll();
            deSearch.Dispose();
            rescoll.Dispose();
          }
          catch (Exception obj)
          {
            System.Console.WriteLine("Exception in getting results. {0}",obj.Message);
          }
        }
}

This will not only dispose of the DirectoryEntry but will also clean up everything else in the using block for you.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM