12

COM Interop ライブラリで C# を使用して、一連の非常に重い Excel ワークブックを開こうとしています。C# を使用する必要があります。これは、マクロを開始し、いくつかのセルを移動し、会社で使用するカスタム Excel アドインを開始する必要があるためです。

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

問題は、私の C# プログラムが終了すると、時間の経過とともに、元の 500 MB から 3.5 ギガのメモリを消費するまで、Excel ワークブックが徐々に多くのメモリを消費することです。

以前はワークブックを手動で開いていましたが、シートがそれほど多くのメモリを消費することはありませんでした。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;
4

1 に答える 1

18

MS Office COM相互運用ライブラリを使用する場合、メモリリークを回避するために私が遭遇したことがいくつかあります。

まず、「2つのドットを使用しない」がそれを覚える最良の方法ですが、基本的には、Intellisenseが推奨している場合でも、常に新しいCOMオブジェクト参照を新しい変数に割り当て、メンバーをチェーン呼び出ししないでください。連鎖呼び出しは、.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を使用するたびにこのスキームを使用することで、メモリの問題は解決しましたが、退屈で悲しいことに、チェーンメンバーを以前のように使用することはできません。

于 2012-11-20T23:07:51.743 に答える