使用DirectorySearcher.FindAll当内存泄漏()内存、DirectorySearcher、FindAll

2023-09-02 10:46:48 作者:Only care(只是在乎)

我有一个需要做大量的查询Active Directory的经常一个长期运行的进程。为此,我一直在使用System.DirectoryServices命名空间,使用DirectorySearcher从和的DirectoryEntry类。我已经注意到,在应用程序中的内存泄漏。

I have a long running process that needs to do a lot of queries on Active Directory quite often. For this purpose I have been using the System.DirectoryServices namespace, using the DirectorySearcher and DirectoryEntry classes. I have noticed a memory leak in the application.

它可以进行复制,这code:

It can be reproduced with this code:

while (true)
{
    using (var de = new DirectoryEntry("LDAP://hostname", "user", "pass"))
    {
        using (var mySearcher = new DirectorySearcher(de))
        {
            mySearcher.Filter = "(objectClass=domain)";
            using (SearchResultCollection src = mySearcher.FindAll())
            {
            }            
         }
    }
}

该文档这些类说,他们会泄漏内存,如果的Dispose()没有被调用。我曾尝试不处理为好,它只是泄漏的更多内存在这种情况下。我已经测试这与两个框架版本2.0和4.0有没有人碰到这个?有什么解决方法?

The documentation for these classes say that they will leak memory if Dispose() is not called. I have tried without dispose as well, it just leaks more memory in that case. I have tested this with both framework versions 2.0 and 4.0 Has anyone run into this before? Are there any workarounds?

更新:我想在另一个AppDomain中运行code,它似乎并没有帮助的。

Update: I tried running the code in another AppDomain, and it didn't seem to help either.

推荐答案

奇怪,因为它可能是,它似乎是内存泄漏只要你不这样做的搜索结果中会出现什么。修改中的问题code如下不会泄露任何内存:

As strange as it may be, it seems that the memory leak only occurs if you don't do anything with the search results. Modifying the code in the question as follows does not leak any memory:

using (var src = mySearcher.FindAll())
{
   var enumerator = src.GetEnumerator();
   enumerator.MoveNext();
}

这似乎是由内部searchObject领域造成有延迟初始化,看着SearchResultCollection与反射器:

This seems to be caused by the internal searchObject field having lazy initialization , looking at SearchResultCollection with Reflector :

internal UnsafeNativeMethods.IDirectorySearch SearchObject
{
    get
    {
        if (this.searchObject == null)
        {
            this.searchObject = (UnsafeNativeMethods.IDirectorySearch) this.rootEntry.AdsObject;
        }
        return this.searchObject;
    }
}

除非searchObject初始化的dispose不会关闭非托管的句柄。

The dispose will not close the unmanaged handle unless searchObject is initialized.

protected virtual void Dispose(bool disposing)
{
    if (!this.disposed)
    {
        if (((this.handle != IntPtr.Zero) && (this.searchObject != null)) && disposing)
        {
            this.searchObject.CloseSearchHandle(this.handle);
            this.handle = IntPtr.Zero;
        }
    ..
   }
}

在ResultsEnumerator调用MoveNext的调用SearchObject的集合从而确保其妥善处理为好。

Calling MoveNext on the ResultsEnumerator calls the SearchObject on the collection thus making sure it is disposed properly as well.

public bool MoveNext()
{
  ..
  int firstRow = this.results.SearchObject.GetFirstRow(this.results.Handle);
  ..
}

在我的应用程序泄漏是由于一些其他的非托管的缓冲区不是被释放正确的测试,我做了误导性的。现在的问题解决了。

The leak in my application was due to some other unmanaged buffer not being released properly and the test I made was misleading. The issue is resolved now.