C# Excel 自动化导致 Excel 内存泄漏

标签 c# excel com automation interop

我正在尝试将 C# 与 COM Interop 库结合使用来打开一组非常繁重的 excel 工作簿。我必须使用 C#,因为我还需要启动宏,四处移动一些单元格,并启动我公司使用的自定义 excel 插件。

然后我的程序退出,工作簿保持打开状态,每个工作簿都在一个单独的 excel 实例中。我不希望在程序退出时关闭工作簿。

问题是,当我的 C# 程序退出时,随着时间的推移,excel 工作簿会逐渐消耗更多内存,直到它们从最初的 500 MB 消耗 3.5 GB 的内存。

我过去常常手动打开工作簿,而工作表从来没有占用那么多内存。一旦我开始使用 C# 打开它们,它们就会因为极端的内存使用而开始崩溃。我的理论是,当我与 COM Excel 对象交互时,我会以某种方式造成内存泄漏。

下面是我的原代码:

using Excel = Microsoft.Office.Interop.Excel;
...
excelApp = new Excel.Application();
excelApp.Visible = true;
excelApp.Workbooks.Open(filename, misValue, misValue, misValue, misValue, misValue,
               true, misValue, misValue, misValue, misValue, misValue, misValue, misValue, misValue);
excelApp.Calculation = Excel.XlCalculation.xlCalculationAutomatic;

我了解到您需要如何使用 Marshal 来发布使用,所以我现在正在尝试以下代码,但没有简单的方法来测试它,除了打开所有工作表并查看它们是否消耗了太多数据。

            excelApp = new Excel.Application();
            excelApp.Visible = true;
            Excel.Workbooks currWorkbooks = excelApp.Workbooks;
            Excel.Workbook currWorkbook = currWorkbooks.Open(filename, misValue, misValue, misValue, misValue, misValue,
               true, misValue, misValue, misValue, misValue, misValue, misValue, misValue, misValue);
            //excelApp.Calculation = Excel.XlCalculation.xlCalculationAutomatic;

            int x = Marshal.ReleaseComObject(currWorkbook);
            currWorkbook = null;

            int y = Marshal.ReleaseComObject(currWorkbooks);
            currWorkbooks = null;

最佳答案

在使用 MS Office COM Interop 库时,我遇到了几件事来避免内存泄漏:

首先,“不要使用两个点”是最好的内存方式,但基本上,始终将新的 COM 对象引用分配给新的变量,不要链式调用成员,即使 Intellisense 鼓励这样做。链式调用在后台做了一些事情,阻止了 .NET 框架的正确发布。这是我用来启动 Excel 报告的一些代码:

//use vars for every COM object so references don't get leftover
//main Excel app
var excelApp = new Application();
var workbooks = excelApp.Workbooks;

//workbook template
var wbReport = workbooks.Add(@"C:\MyTemplate.xltx");

//Sheets objects for workbook
var wSheetsReport = wbReport.Sheets;
var wsReport = (Worksheet)wSheetsReport.get_Item("Sheet1");

其次,为以创建的相反顺序创建的每个变量调用 Marshal.ReleaseComObject(),并在此之前调用几个垃圾收集方法:

//garbage collector
GC.Collect();
GC.WaitForPendingFinalizers();

//cleanup
Marshal.ReleaseComObject(wsReport);
Marshal.ReleaseComObject(wSheetsReport);
Marshal.ReleaseComObject(wbReport);
Marshal.ReleaseComObject(workbooks);
Marshal.ReleaseComObject(excelApp);

每次我使用 Excel 时都使用这个方案解决了我的内存问题,虽然这很乏味和悲伤,但我们不能像我们习惯的那样使用链式成员。

关于C# Excel 自动化导致 Excel 内存泄漏,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13483523/

相关文章:

c++ - 如何正确地将 _bstr_t 重置为 `NULL`

c# - 是否可以在 C# 中返回对变量的引用?

c# - 使用相同应用程序服务的多个应用程序

c# - Resharper 的 'Possible Multiple enumeration of IEnumerable warning'

excel - 在 Excel VBA 的 HTTP 请求中添加哪些引用

vba - MS Office 2013 - VBA 密码安全

COM:如何处理特定的异常?

c# - 如何优雅地防止 web 服务代理暴露给 COM?

c# - 从 List<KeyValuePair<string,string>> 返回匹配项

excel - Excel 是否具有等效的 SQL 聚合函数?