是否有必要处理每个ManagementObject?

时间:2013-03-29 05:08:21

标签: c# wmi

我注意到ManagementObjectIDisposable,但它也是从ManagementClass.GetInstances()ManagementObjectSearcher.Get()返回的,这是否意味着我需要处理遇到的每个对象?

像这样:

ManagementObject ret;
foreach(ManagementObject mo in searcher.Get()) {
    if( IsWhatIWant(mo) ) ret = mo;
    else mo.Dispose();
}

进一步混淆了这一点:ManagementBaseObject中存在一个错误,它无法正确实现IDisposable(请参阅Using clause fails to call Dispose?),因此您需要自己调用它,或者使用它周围的包装器确实正确地称之为。

这很烦人,因为我有很多ManagementObjectCollections

4 个答案:

答案 0 :(得分:3)

  

这很烦人,因为我有很多ManagementObjectCollections。

这与调用Dispose()无关,它只释放底层的非托管COM对象。 ManagementObjectCollection是托管类,它的实例是垃圾回收。这是自动的,你只能通过调用GC.Collect()来帮助。你的程序可能只是创建了很多System.Management对象,可能是因为这是它唯一做过的事情。引用的错误已在我已安装在我的计算机上的当前版本的.NET 3.5SP1和.NET 4.5中修复。

因此,如果您没有.NET的修补版本,那么您不仅会在GC堆上看到很多System.Management对象,您的进程也会消耗大量非托管内存。如果垃圾收集器运行不够频繁,那么可能导致程序与OOM崩溃。你没有提到它是一种失败模式,所以没有强烈表明你有一个真正的问题。

GC堆的第0代的初始大小是2兆字节,它可以增长到8+兆字节。这是一个很多的ManagementObjectCollections对象,它是一个非常小的对象,在32位模式下只占用24个字节。实际的集合是不受管理的。使用Perfmon.exe或内存分析器检查垃圾收集器是否运行得足够频繁。如果没有,那么请关注程序的VM大小。如果那是膨胀,那么在查询循环中使用计数器并在足够高时调用GC.Collect()是一种可行的解决方法。小心你从内存分析器中获取的信息,它可能会因为错误的原因而烦恼。

答案 1 :(得分:2)

我已经创建了一个帮助对象来处理所有创建的管理对象:

public class ManagementObjectDisposer : IDisposable
{
    private List<IDisposable> disposables = new List<IDisposable>();

    /// <summary>
    /// Workaround to dispose ManagementBaseObject properly.
    /// See http://stackoverflow.com/questions/11896282
    /// </summary>
    /// <param name="disposable"></param>
    public static void DisposeOne(IDisposable disposable)
    {
        ManagementBaseObject mbo = disposable as ManagementBaseObject;
        if (mbo != null)
            mbo.Dispose();
        else
            disposable.Dispose();
    }

    public void Dispose()
    {
        Exception firstException = null;
        foreach (IDisposable d in Enumerable.Reverse(disposables))
        {
            try
            {
                DisposeOne(d);
            }
            catch (Exception ex)
            {
                if (firstException == null)
                    firstException = ex;
                else
                    cvtLogger.GetLogger(this).Error($"Swallowing exception when disposing: {d.GetType()}", ex);
            }
        }
        disposables.Clear();
        if (firstException != null)
            throw firstException;
    }

    public T Add<T>(T disposable) where T : IDisposable
    {
        disposables.Add(disposable);
        return disposable;
    }

    /// <summary>
    /// Helper for ManagementObjectSearcher with adding all objects to the disposables.
    /// </summary>
    /// <param name="query">The query string.</param>
    public IEnumerable<ManagementBaseObject> Search(string query)
    {
        ManagementObjectSearcher searcher = this.Add(new ManagementObjectSearcher(query));
        return EnumerateCollection(searcher.Get());
    }

    /// <summary>
    /// Helper for adding ManagementObjectCollection and enumerating it.
    /// </summary>
    public IEnumerable<ManagementBaseObject> EnumerateCollection(ManagementObjectCollection collection)
    {
        this.Add(collection);
        ManagementObjectCollection.ManagementObjectEnumerator enumerator = this.Add(collection.GetEnumerator());
        while (enumerator.MoveNext())
            yield return this.Add(enumerator.Current);
    }
}

只需使用它:

using (var moDisposer = new ManagementObjectDisposer())
{
    foreach (var mobj = moDisposer.Search("SELECT * FROM Win32_Processor")
        Console.WriteLine(mobj["DeviceID"]);
}

注意:ManagementClass.GetInstances()也很容易添加到ManagementObjectDisposer

答案 2 :(得分:1)

实际上代码来自:

http://referencesource.microsoft.com/#System.Management/managementobjectcollection.cs

以及Microsoft Symbol Server中的符号

http://msdl.microsoft.com/download/symbols

暗示ManagementObjectCollection是IDisposable,这意味着它出于某种原因使用非托管资源或者使用IDisposable接口时使用不正确。

答案 3 :(得分:0)

如果您执行很多WMI查询,则应始终处置返回appended_df = df1.append(df2) appended_df a b c 0 1 2 1.0 1 10 20 0.0 0 1 2 NaN 1 10 20 NaN appended_df['c'] = appended_df.c.astype(bool) appended_df a b c 0 1 2 True 1 10 20 False 0 1 2 True 1 10 20 True ,以避免违反配额的情况。

ManagementObjectCollection