2012-11-20 13 views
10

Próbuję użyć C# z biblioteką Interop COM, aby otworzyć zestaw bardzo ciężkich skoroszytów programu Excel. Muszę użyć C#, ponieważ muszę również uruchomić makra, przenieść niektóre komórki i uruchomić niestandardowy dodatek excel-add-in, którego używa moja firma.Automatyzacja C# Excel powoduje przeciek pamięci Excela

Mój program następnie wychodzi, pozostawiając otwarte skoroszytów, każdy w osobnej wersji programu Excel. NIE chcę, aby skoroszyty zostały zamknięte po wyjściu programu.

Problem polega na tym, że po wyjściu mojego programu C# z czasem skoroszyt programu Excel stopniowo zużywa więcej pamięci, aż pobiera 3,5 GB pamięci z oryginalnego 500 MB.

Kiedyś otwierałem skoroszyty ręcznie, a arkusze nigdy nie zużywały tak dużo pamięci. Kiedy zacząłem je otwierać za pomocą C#, zaczęły się łamać z powodu ekstremalnego wykorzystania pamięci. Moja teoria jest taka, że ​​kiedy wchodzę w interakcję z obiektem COM Excel, tworzę przeciek pamięci.

Poniżej jest mój oryginalny kod:

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; 

czytałem o tym, jak trzeba korzystać z marszałkiem zwolnić zastosowań, więc jestem teraz próbuje poniższy kod, ale nie ma łatwego sposobu, aby go przetestować, inne niż otwarcie wszystkich arkuszy i sprawdzenie, czy zużywają zbyt dużo danych.

  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; 
+0

Już ustawiłeś currWorkbook na wartość null .. więc dlaczego robisz to dwa razy. również Mashal.ReleaseComObject (currWorkBook) to wszystko, czego potrzebujesz, aby spróbować przypisać Int do sprawdzenia, czy obiekt został zwolniony, czy też nie. Czy otrzymujesz jakiekolwiek błędy? – MethodMan

+0

Nie otrzymuję żadnych błędów. Problem polega na tym, że skoroszyty podręczne zostały uruchomione w ten sposób, powoli zużywają coraz więcej pamięci. – user804649

+0

Możesz chcieć sprawdzić EPPlus (http://epplus.codeplex.com/). Nie jestem pewien, jaki rodzaj obsługi makr ma wsparcie (wspomina o VBA jako funkcji), ale ogólnie rzecz biorąc, uważam, że EPPlus jest znacznie bardziej wydajny i mniej podatny na awarie niż Excel Interop. – devuxer

Odpowiedz

16

Przy użyciu biblioteki MS Office modelu COM, istnieje kilka rzeczy, na jaki natknąłem się uniknąć przecieków pamięci:

Po pierwsze, „Nie używaj dwie kropki” jest najlepszy sposób na zapamiętanie go, ale w zasadzie zawsze przypisuj nowe odwołanie do obiektu COM do nowej zmiennej, nie łącz się z członkami sieci, nawet jeśli Intellisense to zachęca. Przykuty powołanie robi pewne rzeczy w tle, który uniemożliwia prawidłowe wydzielanie przez NET .. Oto kod używać do uruchamiania raportu 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"); 

drugie, zadzwoń Marshal.ReleaseComObject() dla każdej zmiennej utworzonej w odwrotnej kolejności tworzenie i zadzwonić kilka metod zbierania śmieci przed wykonaniem tak:

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

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

Używanie tego programu za każdym razem używam Excel rozwiązał moje problemy z pamięcią, choć jest nudny i smutny nie możemy używać powiązanej członków do jakiego jesteśmy przyzwyczajeni.

+4

Aby uzyskać więcej informacji, zobacz ten świetny Q/A: http://stackoverflow.com/questions/158706/how-to-properly-clean-up-excel-interop-objects. Pamiętaj, że niektóre z późniejszych odpowiedzi mogą być lepsze niż zaakceptowana odpowiedź. – devuxer

+0

Ach, to może być miejsce, w którym wybrałem nawyki. Nie pamiętałem, gdzie to przeczytałem, tak dawno temu, więc właśnie odpowiedziałem ... To połączenie jest prawdopodobnie najlepszą rzeczą do przeczytania. :) –

+0

+1 Czytałem w kilku miejscach, że używanie "dwóch kropek" nie było dobre, ale nie wiedziałem dlaczego. Teraz ja robię! –