DOBON.NET DOBON.NETプログラミング掲示板過去ログ

EXCELのメモリ開放についての質問

環境/言語:[WindowsXP,VB.NET,.NET Framework1.1]
分類:[.NET]

お世話になります。

よくある質問で申し訳ありません。

EXCEL出力後にどうしてもメモリが開放されないので質問させていただきました。

過去ログなどを参照して、いろいろと試してみたのですがどうにもなりません。

SYSTEM.GC.COLLECTやオブジェクトの参照の開放などは行っているつもりなのですが・・・。

以下が問題のソースなのですが、どうも
objWorkBook = objExcel.Workbooks.Open("C:\TEST.xls")
が怪しいみたいです。
objWorkBookの参照はNothingしているのですが、なぜかメモリは開放されません。

どなたか、御教授いただけますよう宜しくお願い致します。


−−−−−− ソース −−−−−−
Dim objExcel As Excel.Application
Dim objWorkBook As Excel.Workbook
Dim objWorkSheet As Excel.Worksheet

Try
objExcel = New Excel.Application

objWorkBook = objExcel.Workbooks.Open("C:\TEST.xls")

〜 処理 〜

Finally
If Not (objWorkSheet Is Nothing) Then
System.Runtime.InteropServices.Marshal.ReleaseComObject(objWorkSheet)
objWorkSheet = Nothing
End If

If Not (objWorkBook Is Nothing) Then
objWorkBook.Close()
System.Runtime.InteropServices.Marshal.ReleaseComObject(objWorkBook)
objWorkBook = Nothing
End If

objExcel.Quit()
System.Runtime.InteropServices.Marshal.ReleaseComObject(objExcel)
objExcel = Nothing

GC.Collect()

End Try


−−−−−− ここまで −−−−−−−
> SYSTEM.GC.COLLECTやオブジェクトの参照の開放などは行っているつもりなのですが・・・。
GC.Collect は無くても良いので、Marshal.ReleaseComObject() を必ず呼びましょう。

> 以下が問題のソースなのですが、どうも
>    objWorkBook = objExcel.Workbooks.Open("C:\TEST.xls")
> が怪しいみたいです。
> objWorkBookの参照はNothingしているのですが、なぜかメモリは開放されません。

Workbookオブジェクトは解放してありますが、
Workbooksオブジェクトは解放されていませんよね。

  Books = objExcel.Workbooks
  Book = Books.Open("C:\TEST.xls")

のように、それぞれを変数に受け、両者とも Marshal.ReleaseComObject してください。
魔界の仮面弁士さん、早速のご回答ありがとうございます。

おっしゃる通りにソースを修正すると、うまく開放されました。ありがとうございます。

ところで、先の8617で私が掲載致しましたソースで、「〜 処理 〜」とあるとおもうのですが、この部分に次はWorkSheetを使用するソースを追加すると、やはりメモリリークが発生してしまいます。

以下が問題のソースなのですが、OpenしたばかりのobjWorkBookのシート1をobjWorkSheetに(参照を)代入しているだけです。
直後にはMarshal.ReleaseComObjectやNothingも行っています。

度々申し訳ありませんが、御教授願えないでしょうか?
どうぞ宜しくお願いいたします。

objWorkSheet = objWorkBook.Sheets(1)
System.Runtime.InteropServices.Marshal.ReleaseComObject(objWorkSheet)
objWorkSheet = Nothing
> objWorkSheet = objWorkBook.Sheets(1)
> System.Runtime.InteropServices.Marshal.ReleaseComObject(objWorkSheet)
> objWorkSheet = Nothing

・・・・
objWorkSheets = objWorkBook.Sheets
objWorkSheet = objWorkSheets(1)
ReleaseComObject(objWorkSheet)
ReleaseComObject(objWorkSheets)
中 博俊さんご回答ありがとうございます。

> ・・・・
> objWorkSheets = objWorkBook.Sheets
> objWorkSheet = objWorkSheets(1)
> ReleaseComObject(objWorkSheet)
> ReleaseComObject(objWorkSheets)

について、私もやってみたのですが、
objWorkSheets = objWorkBook.Sheets
を行うと、型変換でエラーが発生してしまいます。
objWorkBook.Worksheets
でもだめでした。
objWorkBook.SheetsはReadOnlyなプロパティだからでしょうか???
この手の解放忘れは、「Workbooks」や「Worksheets」だけでなく、
   Cellsプロパティ
   Bordersプロパティ
   Rowsプロパティ
   Columnsプロパティ
などのコレクションオブジェクトでも見落としがちなので、注意してください。


たとえば Cellsプロパティを例に出すと、
  oRange = DirectCast(oSheet.Cells(1, 1), Excel.Range)
        :
  Marshal.ReleaseComObject(oRange)
のように記述した場合、オブジェクトが解放されません。

この場合は、
  oCells = oSheet.Cells
  oRange = DirectCast(oCells._Default(1, 1), Excel.Range)
        :
  Marshal.ReleaseComObject(oRange)
  Marshal.ReleaseComObject(oCells)
などとする必要があるわけです。

# oCells._Default(1, 1) は、単に oCells(1, 1) でも OK です。
魔界の仮面弁士さん、ご回答ありがとうございます。

親切なご説明に大変感謝しております。

「とにかく、変数に参照を渡して、最後に開放する」

これを肝に銘じておきます。

最後に、もう一つ質問させてください。

objWorkBookがExcel.WorkBookのインスタンスへの参照を持ち、objWorkSheetsがExcel.WorkSheetsの型を持つ変数であるとする時、
objWorkSheets = objWorkBook.Sheets
はキャストエラーとなります。
なぜ、Excel.WorkSheets型のプロパティ(objWorkBook.Sheets)をキャストできないのでしょうか???

御教授お願いいたします。
> 「とにかく、変数に参照を渡して、最後に開放する」
そうですね。.NET にて COM を使う上では、
Marshal.ReleaseComObject() を忘れないようにしてください。
# 開放 → 解放 のような気もしますが、それはさておき。

> objWorkBookがExcel.WorkBookのインスタンスへの参照を持ち、objWorkSheetsがExcel.WorkSheetsの型を持つ変数であるとする時、
> objWorkSheets = objWorkBook.Sheets
> はキャストエラーとなります。
なると思いますよ。VB.NET環境だけでなく、Excel 97 や 2003 の VBA でも、
それは型変換エラーになりますから。

> なぜ、Excel.WorkSheets型のプロパティ(objWorkBook.Sheets)をキャストできないのでしょうか???
Sheetsプロパティの戻り値がWorksheets 型ではなく、Sheets型だからでは?
皆様、親切なご回答本当にありがとうございました。
解決済み!

DOBON.NET | プログラミング道 | プログラミング掲示板