2012-11-20 28 views
10

非常に重いExcelワークブックのセットを開くために、COM InteropライブラリでC#を使用しようとしています。マクロを起動し、いくつかのセルを移動し、私の会社が使用するカスタムエクセルアドインを開始する必要があるため、C#を使用する必要があります。C#ExcelオートメーションでExcelのメモリリークが発生する

その後、プログラムが終了し、ワークブックが別のExcelインスタンスに開かれたままになります。私は、プログラムの終了時にブックを閉じたくはありません。

問題は、私のC#プログラムが終了すると、元の500 MBから3.5ギガのメモリを消費するまで、エクセルブックが徐々に多くのメモリを消費するということです。

私は手でワークブックを開くのに使っていましたが、シートはあまりメモリを消費しませんでした。一度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; 

ので、私は今、他の、次のコードをしようとしたが、それをテストする簡単な方法がありませんよすべてのシートを開き、データが多すぎるかどうかを確認するよりも

  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

あなたは既にcurrWorkbookをnullに設定しています。なぜ2回それをやっていますか?また、Mashal.ReleaseComObject(currWorkBook)は、オブジェクトが解放されたかどうかをチェックするためにIntを割り当てるのがなぜ必要なのですか?何かエラーが発生していますか? – MethodMan

+0

私は何のエラーもありません。問題はこのように開始されたワークブックを凌駕し、徐々にメモリを消費します。 – user804649

+0

EPPlus(http://epplus.codeplex.com/)をチェックしてみてください。私はそれがどのようなタイプのマクロサポートを持っているのかはよく分かりませんが(VBAは機能として言及しています)、一般的には、ExcelPopusはExcel Interopよりはるかに効率的でトラブルの発生が少ないと言えます。 – devuxer

答えて

16

MS OfficeのCOM相互運用機能のライブラリを使用する場合は、私が遭遇してきた物事のカップルは、メモリリークを避けるためにあります

まず、最善である「2つのドットを使用しないでください」それを覚えておくべきですが、基本的には新しいCOMオブジェクト参照を常に新しい変数に割り当て、Intellisenseがそれを推奨していてもメンバーを連鎖呼び出ししないでください。第二に

//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()を呼び出します:チェーン呼び出しは、.NETフレームワークによって適切なリリースを防ぎ、バックグラウンドでいくつかのものをして...ここではいくつかの私は、Excelレポートを開始するために使用するコードですそうする前に、ガベージコレクションのメソッドのカップルを作成、およびコール:

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

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

我々が連鎖メンバーを使用することはできません退屈で悲しいですが、私はExcelを使用するたびに、私の記憶の問題を解決したこの方式を使用私たちは慣れています。

+4

詳細については、この素晴らしいQ/Aをご覧ください:http://stackoverflow.com/questions/158706/how-to-properly-clean-up-excel-interop-objects後の回答のいくつかは、受け入れられた回答よりも良いかもしれないことに注意してください。 – devuxer

+0

ああ、それは私が習慣を拾った場所かもしれません..私はそれがずっと前にそれを読んだことを覚えていなかったので、私はちょうど答えました...そのリンクはおそらく読むのが一番です。 :) –

+0

+1私はいくつかの場所で "2つのドット"を使用していない良い読んでいたが、私は理由を知らなかった。今私がやります! –

関連する問題