我想问一个回答Mike Rosenblum's answer到this question的问题。问题是关于清理Excel互操作对象。建议的几个解决方案(例如包装器,不使用多个点,杀死excel进程),但我最喜欢Mike Rosenblum's solution这个问题(lengthy article about the topic)。
它基本上说的是你不要太担心浮动的所有参考文献。您只需保留一些主要内容(例如ApplicationClass
,Workbook
和Worksheet
)。您首先调用垃圾收集来清理浮动的所有对象,然后通过调用Marshal.FinalReleaseComObject
(按重要性的相反顺序)显式清理您仍然拥有的主要引用。
现在我有两个问题
第一:如何确定我需要哪些对象来保持参考?在Mike Rosenblum's example中,他只保留Ranges
,Worksheets
,Workbooks
和ApplicationClasses
。
第二:如果有更多的物体,我如何确定清理它们的顺序(即“重要性顺序”)?
提前致谢。
MattC
已经建议,对于订单,唯一重要的是应用程序最后发布。虽然在我的reference中使用了以下句子:“您还应该按重要性的相反顺序发布命名引用:首先是范围对象,然后是工作表,工作簿,最后是Excel应用程序对象。”暗示有更多的排序。
nobugz
建议将所有内容设置为null
然后进行垃圾回收就足够了,但这似乎与Mike Rosenblum's article的以下引用相矛盾:“那么你会认为你可以设置所有变量= Nothing
,然后在最后调用GC.Collect()
,这有时会起作用。但是,Microsoft Office应用程序对于释放对象的顺序很敏感,不幸的是,设置你的变量= Nothing
,然后调用GC.Collect()
并不能保证对象的发布顺序。“
一些额外信息:
在我自己的应用程序中,我用图表做了很多事情。我正在设置很多属性等。据我所知,有很多地方可以创建新的COM对象。我试图确保我从不使用双点,我试图在我完成的所有对象上调用Marshal.FinalReleaseComObject
。我没有使用包装器方法,因为它会引入嵌套的 lot
我的应用完成工作后,EXCEL.exe
没有关闭。但是......当我告诉我的应用程序再次执行相同的工作时,它确实关闭了。当然,新的EXCEL.exe
已经打开但没有关闭。现在我已经删除了Marshal.FinalReleaseComObject
个调用,并且应用程序完全相同。 EXCEL.exe
保留,直到我告诉我的应用重做工作,然后新的EXCEL.exe
启动并停留。
编辑:当我告诉我的应用程序执行其他非COM相关工作时,一段时间EXCEL.exe
消失,但现在没有新的EXCEL.exe
出现。
不确定我可以从中得出什么结论......
答案 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进程。