使用 DirectorySearcher.FindAll() 时的内存泄漏 [英] Memory Leak when using DirectorySearcher.FindAll()

查看:21
本文介绍了使用 DirectorySearcher.FindAll() 时的内存泄漏的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个长时间运行的进程,需要经常对 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.

可以用这个代码重现:

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 中运行代码,但它似乎也没有帮助.

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

推荐答案

尽管很奇怪,但似乎只有在您不对搜索结果执行任何操作时才会发生内存泄漏.将问题中的代码修改如下,不会泄漏任何内存:

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.

这篇关于使用 DirectorySearcher.FindAll() 时的内存泄漏的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆