哪个Excel Interop对象可以清理自己以及通过GC.Collect()清理哪些对象

时间:2009-12-01 12:52:36

标签: c# com garbage-collection excel-interop

问题:

我想问一个回答Mike Rosenblum's answerthis question的问题。问题是关于清理Excel互操作对象。建议的几个解决方案(例如包装器,不使用多个点,杀死excel进程),但我最喜欢Mike Rosenblum's solution这个问题(lengthy article about the topic)。

它基本上说的是你不要太担心浮动的所有参考文献。您只需保留一些主要内容(例如ApplicationClassWorkbookWorksheet)。您首先调用垃圾收集来清理浮动的所有对象,然后通过调用Marshal.FinalReleaseComObject(按重要性的相反顺序)显式清理您仍然拥有的主要引用。

现在我有两个问题 第一:如何确定我需要哪些对象来保持参考?在Mike Rosenblum's example中,他只保留RangesWorksheetsWorkbooksApplicationClasses。 第二:如果有更多的物体,我如何确定清理它们的顺序(即“重要性顺序”)?

提前致谢。


更新1:

MattC已经建议,对于订单,唯一重要的是应用程序最后发布。虽然在我的reference中使用了以下句子:“您还应该按重要性的相反顺序发布命名引用:首先是范围对象,然后是工作表,工作簿,最后是Excel应用程序对象。”暗示有更多的排序。

nobugz建议将所有内容设置为null然后进行垃圾回收就足够了,但这似乎与Mike Rosenblum's article的以下引用相矛盾:“那么你会认为你可以设置所有变量= Nothing,然后在最后调用GC.Collect(),这有时会起作用。但是,Microsoft Office应用程序对于释放对象的顺序很敏感,不幸的是,设置你的变量= Nothing,然后调用GC.Collect()并不能保证对象的发布顺序。“

更新2:

一些额外信息: 在我自己的应用程序中,我用图表做了很多事情。我正在设置很多属性等。据我所知,有很多地方可以创建新的COM对象。我试图确保我从不使用双点,我试图在我完成的所有对象上调用Marshal.FinalReleaseComObject。我没有使用包装器方法,因为它会引入嵌套的 lot 我的应用完成工作后,EXCEL.exe没有关闭。但是......当我告诉我的应用程序再次执行相同的工作时,它确实关闭了。当然,新的EXCEL.exe已经打开但没有关闭。现在我已经删除了Marshal.FinalReleaseComObject个调用,并且应用程序完全相同。 EXCEL.exe保留,直到我告诉我的应用重做工作,然后新的EXCEL.exe启动并停留。

编辑:当我告诉我的应用程序执行其他非COM相关工作时,一段时间EXCEL.exe消失,但现在没有新的EXCEL.exe出现。

不确定我可以从中得出什么结论......

3 个答案:

答案 0 :(得分:3)

您应该可以在代码中找到可能的实时引用,它们将是您的类中的字段。或者清理方法中的局部变量,这是不太可能的。链接中提供的列表只是您最有可能存储在字段中的对象。可能还有其他人,他们会保持Excel和Application对象一样活着。

我认为我不推荐链接中提倡的手提钻方法,它只是隐藏了一个包含死COM接口的RCW的潜在生命参考。最好的是你可能会永久性地泄漏到RCW对象,最坏的情况是当程序意外引用该对象时会导致程序崩溃。可以肯定的是,Bugz不是你很容易发现的。您所要做的就是将引用设置为null,顺序无关紧要,然后收集。

答案 1 :(得分:2)

我遇到了类似的问题,这就是我的追捕,最后看起来像是为了清理。我希望它有所帮助。

        .......

        oWB._SaveAs(strCurrentDir +
           strFile, XlFileFormat.xlWorkbookNormal, null, null, false, false,       XlSaveAsAccessMode.xlShared, false, false, null, null);
            sumsheet.Activate();
            oWB.Close(null, null, null);
            oXL.Workbooks.Close();
            oXL.Quit();
        }
        catch (Exception theException)
        {
            theException.ToString();
        }
        #region COM Object Cleanup
        finally
        {
            // Cleanup
            GC.Collect();
            GC.WaitForPendingFinalizers();

            System.Runtime.InteropServices.Marshal.FinalReleaseComObject(oRng);
            //System.Runtime.InteropServices.Marshal.FinalReleaseComObject(sumSheet);
            //System.Runtime.InteropServices.Marshal.FinalReleaseComObject(oSheet);
            //oWB.Close(null, null, null);
            System.Runtime.InteropServices.Marshal.FinalReleaseComObject(oWB);
            oXL.Quit();
            System.Runtime.InteropServices.Marshal.FinalReleaseComObject(oXL);
        }
        #endregion

修改

如果您注意到我已经注释掉了sumSheet + oSheet(这是我的工作表),因为它不需要。这段代码对我来说没有任何问题。我通过重新安排顺序找到了错误。

答案 2 :(得分:0)

我认为只要应用程序是最后一个,您可以按任何顺序释放它们(只要它们不为空)。

然后执行GC.Collect以最终终止excel.exe进程。