Автоматизация С# Excel вызывает утечку памяти Excel

Я пытаюсь использовать С# с библиотекой COM Interop, чтобы открыть набор очень тяжелых книг excel. Я должен использовать С#, потому что мне также нужно запускать макросы, перемещать несколько ячеек и запускать пользовательское дополнение excel, которое использует моя компания.

Моя программа затем выходит, оставляя рабочие книги открытыми, каждый в отдельном экземпляре excel. Я НЕ хочу, чтобы книги были закрыты, когда программа выходит.

Проблема заключается в том, что, когда моя программа С# выходит, со временем книги Excel превосходят все больше памяти, пока они не потребляют 3,5 гигабайта памяти с оригинальной 500 мб.

Раньше я открывал книги, и листы никогда не потребляли столько памяти. Как только я начал открывать их с помощью С#, они начали ломаться из-за чрезмерного использования памяти. Моя теория заключается в том, что каким-то образом, когда я взаимодействую с объектом 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;

Я читал о том, как вам нужно использовать маршал для выпуска приложений, поэтому теперь я пытаюсь выполнить следующий код, но не имею простого способа проверить его, кроме открытия всех листов и просмотра, если они потребляют слишком много данных.

            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;

Ответ 1

При использовании библиотек MS Office COM Interop есть несколько вещей, которые я обнаружил, чтобы избежать утечек памяти:

Во-первых, "Не использовать две точки" - это лучший способ запомнить его, но в основном всегда назначайте новую ссылку COM-объекта на новую переменную, не вызывайте цепочку вызовов, даже если Intellisense ее поощряет. Прикованный вызов делает некоторые вещи в фоновом режиме, которые препятствуют правильному выпуску .NET framework. Вот какой код я использую для запуска отчета 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, я решил проблемы с памятью, хотя утомительно и грустно мы не можем использовать прикованных членов так, как мы привыкли.