Автоматизация С# 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, я решил проблемы с памятью, хотя утомительно и грустно мы не можем использовать прикованных членов так, как мы привыкли.