Wednesday, December 22, 2004

Memory Leak using DirectorySearcher .FindOne()?

I remember Joe Kaplan telling me one time that there was a memory leak when using the .FindOne() method of the DirectorySearcher. I also believe Max Vaughn from MS told me the same thing, now that I think about it. I decided to dig a little bit more into this and figure out what was actually wrong. It turns out that this bug will only really affect you when you are doing a lot of searches and not finding any results. That's right, I said not finding any results. A quick look using Reflector and we can see why this is:

            public SearchResult FindOne()
            {
                SearchResultCollection collection1 = this.FindAll(false);
                foreach (SearchResult result1 in collection1)
                {
                    collection1.Dispose();
                    return result1;
                }
                return null;
            }

As you can see, the .Dispose() is only called when at least one SearchResult is found. If no SearchResult is found, then the SearchResultCollection hangs onto its unmanaged resource. What's the fix? It is a pretty simple fix actually - just make sure you always call .Dispose() on your SearchResultCollection by using the .FindAll() method instead:

        public static SearchResult FindOne( DirectorySearcher ds )
        {
            SearchResult sr = null;

            using (SearchResultCollection src = ds.FindAll())
            {
                if (src.Count > 0)
                {
                    sr = src[0];
                }
            }
            return sr;
        }


Note, for those unfamiliar with C# syntax, the 'using' statement will call .Dispose() in a try/finally manner at the last brace.