C# と VB.NET の質問掲示板

ASP.NET、C++/CLI、Java 何でもどうぞ

C# と VB.NET の入門サイト

Re[8]: Excelのメモリ開放について(遅延バインディング方式)


(過去ログ 52 を表示中)

[トピック内 13 記事 (1 - 13 表示)]  << 0 >>

■29001 / inTopicNo.1)  Excelのメモリ開放について(遅延バインディング方式)
  
□投稿者/ blueblur (1回)-(2008/12/03(Wed) 11:35:28)

分類:[.NET 全般] 

開発環境:Windows VS.NET 2005
使用言語:VB.NET

タイトルの件について質問させていただきます。

【事象】
今保守中のプロジェクトはExcelファイル出力処理が多数存在し、
Excel操作には遅延バインディングを使うことになっています(開発規約として)。
使用後のオブジェクトは基本的に○○ = Nothingのように開放しています。
Excelは問題なく終了できますが、気のせいかもしれませんが、
連続して複数回実行したうちにだんだん出力速度が落ちていくような気がします。

ソースを精査した結果、下記のような実装があると判明しました。
パターン1.Dim s As String = MySheet.Range("A1:A3").Value 
パターン2.SetValue(MySheet.Range("A1:A3"), "サンプル")

SetValueの定義は以下です。
Private Sub SetValue(ByRef p_Range As Object, ByVal p_Value As String)
If p_Range IsNot Nothing
p_Range.Value = p_Value
(以下書式設定など省略)
End If
End Sub

【質問】
MySheet.Range("A1:A3")は開放されていません。
しかし上記の場合、開放する必要がありますか。
システムの裏の動きはどうなっていますか。
Excelに限らず、どのタイミングでメモリー開放の必要が生じるか知りたいです。

まったく初歩的な質問ですみませんがご教授ください。
または関連資料のリンクをご提示いただければと思います。
よろしくお願いいたします。
引用返信 編集キー/
■29007 / inTopicNo.2)  Re[1]: Excelのメモリ開放について(遅延バインディング方式)
□投稿者/ まさる (35回)-(2008/12/03(Wed) 12:02:47)
まさる さんの Web サイト
まずはこちらを一読することをお勧めします。

http://jeanne.wankuma.com/tips/vb.net/excel/
引用返信 編集キー/
■29014 / inTopicNo.3)  Re[2]: Excelのメモリ開放について(遅延バインディング方式)
□投稿者/ blueblur (2回)-(2008/12/03(Wed) 12:41:42)
No29007 (まさる さん) に返信
> まずはこちらを一読することをお勧めします。
>
> http://jeanne.wankuma.com/tips/vb.net/excel/

ご返信ありがとうございます。
「COM オブジェクトの参照カウントを解放する」も含めて読ませていただきました。

非遅延バインディング方式なら、
本文に記述したソースでは下記のように修正する認識です。
パターン1.
Dim r as Range = MySheet.Range("A1:A3")
Dim s As String = r.Value
ReleaseComObject(r)
r = Nothing 

パターン2.
呼び出し先の関数内部でReleaseComObjectを実行

ただしVB6時代から多用された遅延バインディング方式では、
(VB.NETでも)InteropなしでNothingを与えるだけで開放できたようです。

非遅延バインディング方式との違い、また内部の仕組みはよくわかりませんので、
質問させていただきました。
引用返信 編集キー/
■29016 / inTopicNo.4)  Re[3]: Excelのメモリ開放について(遅延バインディング方式)
□投稿者/ 魔界の仮面弁士 (930回)-(2008/12/03(Wed) 12:56:25)
2008/12/03(Wed) 14:40:05 編集(投稿者)

No29014 (blueblur さん) に返信
> ただしVB6時代から多用された遅延バインディング方式では、
むしろ、型変換にともなって参照カウントが増加するなどの理由から、
レイトバインドの方が、解放が難しくなる事さえありえます。

例えば、
  Dim Hs As Excel.HPageBreaks = objSheet1.HPageBreaks
  Dim H As Excel.HPageBreak = Hs.Add(objRange)
  Marshal.ReleaseComObject(H)
  Marshal.ReleaseComObject(Hs)
  Marshal.ReleaseComObject(objRange)
  Marshal.ReleaseComObject(objSheet1)
ならば正しく解放されたコードが、参照設定無しだと
  Dim Hs As Object = objSheet1.HPageBreaks
  Dim H As Object = Hs.Add(objRange) 'ここで参照カウントが増加してしまう。
  Marshal.ReleaseComObject(H)
  Marshal.ReleaseComObject(Hs)
  Marshal.ReleaseComObject(objRange) 'そのため、ここで解放してもまだ一つ残っている…。
  Marshal.ReleaseComObject(objSheet1)
という結果になってしまった事がありました。
http://hpcgi1.nifty.com/MADIA/VBBBS2/wwwlng.cgi?print+200512/05120042.txt


> (VB.NETでも)InteropなしでNothingを与えるだけで開放できたようです。
だとしたら、それはただの偶然かも知れません。
(.NET 側のメモリ管理と COM のメモリ管理は別物です)

実際当方では、Nothing 代入による
 Sub Main()
   Dim o As Object = CreateObject("Excel.Application")
   o.Quit()
   MsgBox("これから解放します。", vbSystemModal)
   o = Nothing
   MsgBox("解放されていますか?", vbSystemModal)
 End Sub
というコードにおいて、タスクマネージャ上に「EXECEL.EXE」のプロセスが残ってしまう事を
確認しています。(アプリが終了すれば、続けて解放される可能性がありますけれども)


一方、ReleaseComObject を呼び出した場合においては、アプリを終了させずとも、
ReleaseComObject の呼び出しによって、タスクマネージャ上から「EXECEL.EXE」が
即座に消える事を確認しています。

 Sub Main()
   Dim o As Object = CreateObject("Excel.Application")
   o.Quit()
   MsgBox("これから解放します。", vbSystemModal)
   System.Runtime.InteropServices.Marshal.ReleaseComObject(o)
   MsgBox("解放されていますか?", vbSystemModal)
 End Sub
引用返信 編集キー/
■29035 / inTopicNo.5)  Re[4]: Excelのメモリ開放について(遅延バインディング方式)
□投稿者/ blueblur (4回)-(2008/12/03(Wed) 14:44:22)
No29016 (魔界の仮面弁士 さん) に返信

検証ありがとうございました。

考えてみまた結果、下記認識でよろしいでしょうか。

遅延バインディングかどうかに関係なく、
VS.NETにおいてCOM通信は常に
.NET ⇔ COMラッパ ⇔ COMオブジェクトの形で行われます。

ReleaseComObjectを呼ぶことで即座にCOMオブジェクトを開放できます。

ただし遅延バインディングの場合は明示的にCOMオブジェクトを開放できず、
.NET側の変数をNothingにすると、COMラッパが破棄されますが、
メモリ開放のタイミングはGCに依存していまいます。
(まったく推測)

間違いがあればご指摘お願い致します。
引用返信 編集キー/
■29104 / inTopicNo.6)  Re[5]: Excelのメモリ開放について(遅延バインディング方式)
□投稿者/ 魔界の仮面弁士 (933回)-(2008/12/04(Thu) 13:35:51)
> .NET ⇔ COMラッパ ⇔ COMオブジェクトの形で行われます。
ですます。

> ReleaseComObjectを呼ぶことで即座にCOMオブジェクトを開放できます。
Release を「公開する」の意味で見るならば「開放」とも訳せますが、
この場合は「解放」の方が適切かも……という話は横に置いとくとして。

> ただし遅延バインディングの場合は明示的にCOMオブジェクトを開放できず、
参照設定していたからといって、COM の解放処理を省略できるわけではありません。
事前バインドであれ実行時バインドであれ、ReleaseComObject (またはそれに相当する機能)の
呼び出しは必要となります。

> .NET側の変数をNothingにすると、COMラッパが破棄されますが、
> メモリ開放のタイミングはGCに依存していまいます。
依存しているといえば、確かにその通りですが、
.NET の世界のガベージコレクションと、
COM の世界のガベージコレクションは別物かと。
引用返信 編集キー/
■29108 / inTopicNo.7)  Re[6]: Excelのメモリ開放について(遅延バインディング方式)
□投稿者/ 渋木宏明(ひどり) (973回)-(2008/12/04(Thu) 14:34:03)
渋木宏明(ひどり) さんの Web サイト
>>.NET側の変数をNothingにすると、COMラッパが破棄されますが、

破棄されません。
参照が失われるだけです。

>>メモリ開放のタイミングはGCに依存していまいます。

↑の「メモリ」が「COM ラッパが使用していたメモリ」であるなら、YES。

> COM の世界のガベージコレクションは別物かと。

COM にはガベージコレクションはありません。

引用返信 編集キー/
■29119 / inTopicNo.8)  Re[7]: Excelのメモリ開放について(遅延バインディング方式)
□投稿者/ 魔界の仮面弁士 (934回)-(2008/12/04(Thu) 15:27:24)
2008/12/04(Thu) 15:29:03 編集(投稿者)

No29108 (渋木宏明(ひどり) さん) に返信
>>COM の世界のガベージコレクションは別物かと。
> COM にはガベージコレクションはありません。

そのように書かれた資料(Crispin Goswell氏の物だったかな?)を見た気もするのですが、
その一方で、ActiveX コンポーネントの話をする際に『ガベージ コレクション』という
表現を目にする事もあって(KB416498, KB304227 など)、私自身、あまり細かくは
把握していていなかったりします。

そして勝手に、参照カウントが 0 になった後、使用済みメモリを回収するための
仕組みが、COM の仕様としてあるのかと思いこんでいました。

勉強してきます…。
引用返信 編集キー/
■29120 / inTopicNo.9)  Re[7]: Excelのメモリ開放について(遅延バインディング方式)
□投稿者/ aetos (30回)-(2008/12/04(Thu) 16:14:20)
No29108 (渋木宏明(ひどり) さん) に返信
>>COM の世界のガベージコレクションは別物かと。
>
> COM にはガベージコレクションはありません。

本題じゃないところに突っ込んじゃいますが、「ガベージコレクション」の定義次第ではないですか?
定期的に DllCanUnloadNow を呼びに来てくれる人はガベージコレクタと呼べないでしょうか?
delete よりも若干遅れたタイミングで、タスクマネージャで見える使用メモリ量を減らす人はガベージコレクタとは呼べないでしょうか?
引用返信 編集キー/
■29121 / inTopicNo.10)  Re[8]: Excelのメモリ開放について(遅延バインディング方式)
□投稿者/ chobi (7回)-(2008/12/04(Thu) 16:18:40)
いつも勉強させていただいております。

下記の参照カウント(記事中ほど)読みました。
http://ja.wikipedia.org/wiki/Component_Object_Model

ここから参照カウントへのリンク(下記)なのですが、
http://ja.wikipedia.org/wiki/%E5%8F%82%E7%85%A7%E3%82%AB%E3%82%A6%E3%83%B3%E3%83%88

参照カウントはガベージコレクタの動作方法のひとつとの言い方がされています。
ガベージコレクタの定義があいまいではありますが・・・


引用返信 編集キー/
■29157 / inTopicNo.11)  Re[8]: Excelのメモリ開放について(遅延バインディング方式)
□投稿者/ 渋木宏明(ひどり) (974回)-(2008/12/04(Thu) 20:11:27)
渋木宏明(ひどり) さんの Web サイト
2008/12/04(Thu) 21:11:15 編集(投稿者)
2008/12/04(Thu) 20:14:37 編集(投稿者)

> そして勝手に、参照カウントが 0 になった後、使用済みメモリを回収するための
> 仕組みが、COM の仕様としてあるのかと思いこんでいました。

少なくとも、COM ランタイムの仕組みではありません。

参照カウントが0になった時に、自発的にインスタンスの破棄を行うように取り決められているだけです。

ATL や MFC, VB なんかでは、その実装がライブラリ内部に隠されているから、気付いてないだけの話です。

循環参照を実現する場合など、特殊なケースでは COM 仕様が求めるような参照カウントの運用から外れた実装を行う場合もありえます。

という具合に、あくまで「サーバの実装次第」な動作を「COM の機能」と呼ぶのには、僕は抵抗があります。

# Wiki ペディアの記述は、技術的な根拠としてはちょっと…

引用返信 編集キー/
■29158 / inTopicNo.12)  Re[8]: Excelのメモリ開放について(遅延バインディング方式)
□投稿者/ 渋木宏明(ひどり) (975回)-(2008/12/04(Thu) 20:13:22)
渋木宏明(ひどり) さんの Web サイト
> 定期的に DllCanUnloadNow を呼びに来てくれる人はガベージコレクタと呼べないでしょうか?

拡大解釈しすぎだと思う。

DllCanUnloadNow() の対象は COM オブジェクトのインスタンスではなく、Dll のロードモジュールそのものでしょ?

引用返信 編集キー/
■29159 / inTopicNo.13)  Re[9]: Excelのメモリ開放について(遅延バインディング方式)
□投稿者/ 渋木宏明(ひどり) (976回)-(2008/12/04(Thu) 20:20:35)
渋木宏明(ひどり) さんの Web サイト
2008/12/04(Thu) 21:17:40 編集(投稿者)
2008/12/04(Thu) 20:23:00 編集(投稿者)

> 参照カウントはガベージコレクタの動作方法のひとつとの言い方がされています。
> ガベージコレクタの定義があいまいではありますが・・・

「参照カウンタ」はガベージコレクタの実装手法の一つではあります.

いわゆるガベージコレクタが、不要なメモリ領域の判定に「参照カウンタ」を採用する場合があります。

ですが、COM ランタイムが「参照カウンタによってガベージコレクションを行っている」わけではありません。

>下記の参照カウント(記事中ほど)読みました。
>http://ja.wikipedia.org/wiki/Component_Object_Model

でも明確に記述されていますが、COM では原則として、インスタンスが使用していたメモリ領域はインスタンス自身によって自発的に解放することが求められています。

しかもこれは原則であり、特殊なケースでは実装レベルで異なるメモリ管理が採用されることもあります。

こうった一元化されてないない、自発的な動作をガベージコレクションと呼ぶのは、いささか風呂敷を広げ過ぎな気がします。


引用返信 編集キー/


トピック内ページ移動 / << 0 >>

このトピックに書きこむ

過去ログには書き込み不可

管理者用

- Child Tree -