【问题标题】:Do I need to release the COM object on every 'foreach' iteration?我是否需要在每次“foreach”迭代时释放 COM 对象?
【发布时间】:2010-11-30 19:48:19
【问题描述】:

这是(潜在的)问题:

我创建了一个 COM 对象,然后使用“foreach”遍历它返回的集合中的每个元素。我是否需要释放我在集合中遍历的每个单独元素? (见下面的代码。)如果是这样,我想不出一种方法可以有效地从“finally”语句中释放它,以防在操作项目时出现错误。

有什么建议吗?

private static void doStuff()
{
    ComObjectClass manager = null;

    try
    {
        manager = new ComObjectClass();
        foreach (ComObject item in manager.GetCollectionOfItems())
        {
            Log.Debug(item.Name);
            releaseComObject(item); // <-- Do I need this line?
                                    //     It isn't in a 'finally' block...
                                    //             ...Possible memory leak?
        }
    }
    catch (Exception) { }
    finally
    {
        releaseComObject(manager);
    }
}

private static void releaseComObject(object instance)
{
    if (instance != null)
    {
        try
        {
            System.Runtime.InteropServices.Marshal.ReleaseComObject(instance);
        }
        catch
        {
            /* log potential memory leak */
            Log.Debug("Potential memory leak: Unable to release COM object.");
        }
        finally
        {
            instance = null;
        }
    }
}

【问题讨论】:

    标签: c# com memory-management memory-leaks com-interop


    【解决方案1】:

    您不应将foreach 语句与 COM 对象一起使用,因为在您无法控制释放的幕后进行引用。我会切换到for 循环并确保你never use two dots with COM objects.

    看起来会是这样:

    try
    {
        manager = new ComObjectClass();
        ComObject comObject = null;
        ComObject[] collectionOfComItems = manager.GetCollectionOfItems();
        try
        {
            for(int i = 0; i < collectionOfComItems.Count; i++)
            {
                comObject = collectionOfComItems[i];
                ReleaseComObject(comObject);
            }
        }            
        finally
        {
            ReleaseComObject(comObject);
        }
    }
    finally 
    {
        ReleaseComObject(manager);
    }
    

    【讨论】:

    • 谢谢!这就是我一直在寻找和害怕的答案。
    • 不过,这会使整个循环变慢。
    • @nawfal 为什么这会使循环变慢?
    • 取决于 COM 对象本身,它的实现。当我曾经为 Word 和 Excel 互操作自动化运行 for 循环时,我发现它比运行 foreach 循环慢得多。索引可能不是很好。谁知道,如果它是内部的线性搜索?
    • 我明白了;无论哪种方式,foreach 都会导致内存泄漏。因此,即使它在前面更快,它也会在以后减慢你的速度;-)
    【解决方案2】:

    另一种方法是创建自己的迭代器函数:

    IEnumerable<ComObject> GetChildItems(this ComObjectClass manager) {
        ComObject comObject = null;
    
        ComObject[] collectionOfComItems = manager.GetCollectionOfItems();
        for (int i = 0; i < collectionOfComItems.Length; i++) {
            try {
                comObject = collectionOfComItems[i];
    
                yield return comObject;
            } finally {
                if (comObject != null)
                    Marshal.ReleaseComObject(comObject);
            }
        }
    
        yield break;
    }
    
    private static void doStuff() {
        ComObjectClass manager = null;
    
        try {
            manager = new ComObjectClass();
    
            foreach (ComObject item in manager.GetChildItems()) {
                Log.Debug(item.Name);
            }
        } finally {
            releaseComObject(manager);
        }
    }
    

    我觉得这使您的代码更具可读性,尤其是当您需要多次迭代子项时。

    【讨论】:

      猜你喜欢
      • 2013-11-20
      • 1970-01-01
      • 2021-05-27
      • 2010-11-06
      • 1970-01-01
      • 2012-01-22
      • 2013-10-15
      • 2011-07-01
      相关资源
      最近更新 更多