哪些 Excel Interop 对象要自己清理,哪些要通过 GC.Collect() 清理
问题:
我想针对 Mike Rosenblum 对这个问题的回答< /a>.问题是关于清理 Excel 互操作对象。建议了几种解决方案(例如包装器,不使用多个点,终止 Excel 进程),但我喜欢 Mike Rosenblum 对这个问题的解决方案最多 (关于该主题的长篇文章)。
它基本上说的是,您不必太担心所有浮动的参考文献。您只需保留一些主要的(如 ApplicationClass
、Workbook
和 Worksheet
)。您首先调用垃圾收集来清理所有浮动的对象,然后通过调用 Marshal.FinalReleaseComObject 显式清理仍然拥有的主要引用(按重要性的相反顺序)。
现在我对此有两个问题。
第一:如何确定需要保留哪些对象的引用?在 Mike Rosenblum 的示例中,他仅保留 Ranges
、Worksheets
、Workbooks
和 ApplicationClasses
。
第二:如果对象较多,如何确定清理它们的顺序(即“重要性顺序”)?
提前致谢。
更新1:
MattC
建议,对于订单来说,唯一重要的是应用程序最后发布。尽管在我的参考中,以下内容句子:“您还应该按照重要性的相反顺序释放命名引用:首先是范围对象,然后是工作表、工作簿,最后是 Excel 应用程序对象。”意味着有更多的订购。
nobugz
建议将所有内容设置为 null
然后进行垃圾收集就足够了,但这似乎与 Mike Rosenblum 的文章:“那么,您可能会认为您可以设置所有变量 = Nothing
并且然后在最后调用 GC.Collect() ,这有时确实有效。但是,Microsoft Office 应用程序对对象的释放顺序很敏感,不幸的是,设置变量 = 什么都没有然后调用
GC.Collect()
并不能保证对象的释放顺序。”
更新2:
一些额外信息: 在我自己的应用程序中,我用图表做了很多事情。我设置了很多属性等。据我所知,我在很多地方创建了新的 COM 对象。我试图确保我从不使用双点,并且尝试对我完成的所有对象调用 Marshal.FinalReleaseComObject
。我没有使用包装器方法,因为它会引入大量嵌套。
我的应用程序完成工作后,EXCEL.exe
没有关闭。但是......当我告诉我的应用程序再次执行相同的工作时,它确实关闭了。当然,一个新的EXCEL.exe
打开了,但没有关闭。现在我已经删除了所有 Marshal.FinalReleaseComObject
调用,并且应用程序的工作方式完全相同。 EXCEL.exe
会保留下来,直到我告诉我的应用程序重做工作,但随后新的 EXCEL.exe
会启动并保留。
编辑:此外,当我告诉我的应用程序执行其他非 COM 相关工作时,一段时间后 EXCEL.exe
消失,但现在没有新的 EXCEL.exe
出现。
不确定我能从中得出什么结论......
Question:
I want to ask a question in response to Mike Rosenblum's answer to this question. The question was about cleaning up Excel interop objects. Several solutions where suggested (e.g. wrappers, not using more than one dot, killing the excel process), but I liked Mike Rosenblum's solution to this problem the most (lengthy article about the topic).
What it basically says is that you don't worry too much about all the references floating around. You just keep some main ones (like ApplicationClass
, Workbook
and Worksheet
). You first invoke garbage collection to clean up all the objects floating around and then explicitly clean up the main references you still have by calling Marshal.FinalReleaseComObject
(in reverse order of importance).
Now I have two questions about this.
First: How do I determine to which objects I need to keep a reference? In Mike Rosenblum's example he only keeps Ranges
, Worksheets
, Workbooks
and ApplicationClasses
.
Second: If there are more objects, how do I determine the order of cleaning them up (i.e. the "order of importance")?
Thanks in advance.
Update 1:
It has been suggested by MattC
that for the order, the only thing that is important is that the app is released last. Although in my reference the following sentence:"You should also release your named references in reverse order of importance: range objects first, then worksheets, workbooks, and then finally your Excel Application object." implies that there is more ordering.
nobugz
Suggests that setting everything to null
and then doing garbage collection will suffice, but that seems to contradict the following quote from Mike Rosenblum's article:"You would think, then, that you can set all your variables = Nothing
and then call GC.Collect()
at the end, and this does work sometimes. However, Microsoft Office applications are sensitive to the order in which the objects are released and, unfortunately, setting your variables = Nothing
and then calling GC.Collect()
does not guarantee the release order of the objects."
Update 2:
Some extra info:
In my own application, I do a lot of things with a chart. I am setting a lot of properties etc. As I understand, there are many places where I create new COM objects. I tried to make sure I never use double dots, and I tried to call Marshal.FinalReleaseComObject
on all objects that I am finished with. I didn't use the wrapper approach because it would introduce a lot of nesting.EXCEL.exe
did not close after my app finished its work. But... it did close when I told my app to do the same work again. Of course a new EXCEL.exe
opened which did not close. Now I have removed alllll the Marshal.FinalReleaseComObject
calls and the app works exactly the same. The EXCEL.exe
stays, until I tell my app to redo the work, but then a new EXCEL.exe
starts and stays.
EDIT: Also when I tell my app to do other non-COM related work, after a while the EXCEL.exe
disappears, but now no new EXCEL.exe
appears.
Not sure what conclusions I can draw from this...
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
您应该可以轻松地在代码中找到可能的实时引用,它们将是您的类中的字段。或者清理方法中的局部变量,这是不可能的。链接中提供的列表只是您最有可能存储在字段中的对象。可能还有其他对象,它们将使 Excel 与 Application 对象一样活跃。
我不认为我会推荐链接中所提倡的手提钻方法,它只是隐藏了对包装死 COM 接口的 RCW 的潜在生命引用。最好的情况是,RCW 对象可能会永久泄漏,最坏的情况是,当程序意外引用该对象时,程序会崩溃并出现异常。可以肯定的是,Bugz 并不是您能轻易发现的。您所要做的就是将引用设置为 null,顺序并不重要,然后收集。
You should have no trouble finding possible live references in your code, they will be fields in your class(es). Or local variables in the cleanup method, that's unlikely. The list provided in the link are just objects that you most likely will store in a field. There could be others, they'll keep Excel just as alive as the Application object.
I don't think I'd recommend the jackhammer approach as advocated in the link, it just hides a potential life reference to an RCW that wraps a dead COM interface. A best you'll have a possibly permanent leak to the RCW object, at worst it crashes your program with an exception when it accidentally references the object. Bugz, to be sure, just not ones you'll easily discover. All you have to do is set your references to null, order doesn't matter, then collect.
我也遇到过类似的问题,这就是我捕获的东西,最后看起来是要清理的。我希望它有帮助。
编辑
如果您注意到我已经注释掉了 sumSheet + oSheet(这是我的工作表),因为不需要它。这段代码对我来说很可靠,没有任何问题。我发现通过重新排列顺序我遇到了错误。
I've had a similar problem this is what my catch and finally look like for clean up. I hope it helps.
EDIT
If you noticed I've commented out the sumSheet + oSheet(Which are my worksheets) because it wasn't needed. This code has solid for me with no problems. I've found by rearranging the order I've gotten errors.
我认为只要应用程序是最后一个,您就可以按任何顺序释放它们(只要它们不为空)。
然后执行 GC.Collect 最终杀死 excel.exe 进程。
I think as long as application is last you can release them in any order (as long as they aren't null).
Then do a GC.Collect to finally kill the excel.exe process.