3

问题:

我想问一个问题以回应Mike Rosenblum这个问题的回答。问题是关于清理 Excel 互操作对象。建议的几种解决方案(例如,包装器,不使用多个点,终止 excel 进程),但我最喜欢Mike Rosenblum对这个问题的解决方案(关于该主题的冗长文章)。

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

现在我有两个问题。
第一:我如何确定我需要保留哪些对象的引用?在Mike Rosenblum 的示例中,他只保留Ranges,和. 第二:如果有更多的对象,我如何确定清理它们的顺序(即“重要性顺序”)?WorksheetsWorkbooksApplicationClasses

提前致谢。


更新1:

有人建议MattC,对于订单,唯一重要的是应用程序最后发布。尽管在我的参考资料中有以下句子:“您还应该按重要性相反的顺序释放您的命名参考资料:首先是范围对象,然后是工作表、工作簿,最后是您的 Excel 应用程序对象。” 意味着有更多的排序。

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

更新 2:

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

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

不知道我能从中得出什么结论......

4

3 回答 3

3

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

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

于 2009-12-01T13:43:21.520 回答
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(这是我的工作表),因为它不是必需的。这段代码对我来说很可靠,没有问题。我通过重新排列我得到错误的顺序发现。

于 2009-12-01T13:21:09.963 回答
0

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

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

于 2009-12-01T13:08:05.963 回答