- PR -

COM参照を確実に解放するコードの可読性をあげたい

投稿者投稿内容
囚人
ぬし
会議室デビュー日: 2005/08/13
投稿数: 1019
投稿日時: 2006-03-16 11:25
引用:

しますよ。

ただ、それが「いつ」なのかが問題なのです。


なぬ!確かにファイナライザでは「いつ」という問題はありますが、という事は、マネージコードで増加させた参照カウントは、アプリケーション終了時には参照カウンタは全て減らすという事ですね。

引用:

COM 側に参照を引き渡せばその時点で参照カウントが増加します。
しかも、その参照カウントの増加について、.NET ランタイムは関知しないというのがまた問題の種に。。。


それは頭が痛いですね。それって、自分達で管理して ReleaseComObject で減らそうと思っても、いつ減らせばいいのか分からないのではないですか?

_________________
囚人のジレンマな日々
じゃんぬねっと
ぬし
会議室デビュー日: 2004/12/22
投稿数: 7811
お住まい・勤務地: 愛知県名古屋市
投稿日時: 2006-03-16 11:53
私への返信も似たようなものなんで、話が進んでいるこちらにぶら下げます。

引用:

囚人さんの書き込み (2006-03-16 11:25) より:

なぬ!確かにファイナライザでは「いつ」という問題はありますが、
という事は、マネージコードで増加させた参照カウントは、
アプリケーション終了時には参照カウンタは全て減らすという事ですね。


昨日、どこかにも書きましたが「正常終了時に限り」ですね。
それと、既にリークしている場合がないとも限らなかったり。
↑"そういう" 意味でも自前で参照を取って、責任を持ってしかるべき順番で、
ReleaseComObject していくというのが現状最も安全であると思います。

引用:

それって、自分達で管理して ReleaseComObject で減らそうと思っても、
いつ減らせばいいのか分からないのではないですか?


自分達が CLR なのか我々を指すのかで変わりますが、
使い終わって不要になったら即解放という現状のコーディング スタイルがそれでしょう。

IDisposable.Dispose ということであれば、
Dispose メソッド専用の「別の参照」を取っておき、すべてデクリメントするとか。(;^-^)
ただ、そのラッパークラスのメンバに別の COM へ辿るルートがあると、
"大外で" ラップするだけでは意味がなくなってきます。

_________________
C# と VB.NET の入門サイト
じゃんぬねっと日誌
渋木宏明(ひどり)
ぬし
会議室デビュー日: 2004/01/14
投稿数: 1155
お住まい・勤務地: 東京
投稿日時: 2006-03-16 12:07
引用:

という事は、マネージコードで増加させた参照カウントは、アプリケーション終了時には参照カウンタは全て減らすという事ですね。



減らさなければならないです。

引用:

いつ減らせばいいのか分からないのではないですか?



だから、何でもかんでも ReleaseCOMObject() すればいい、という訳ではないんです。
タイミングは非常に重要です。

前にも書きましたが、マネージラッパが内包している COM オブジェクトの参照を別の COM オブジェクトに渡せば、そこで COM オブジェクトの参照カウントは1増加します。

なので、闇雲に ReleaseCOMObiect() を実行すると、「別の COM オブジェクトが参照を保持しているかもしれない COM オブジェクト」のインスタンスを強制的に解放してしまうことにな兼ねません。

厳密に言えば「COM オブジェクトの参照を別の COM オブジェクトに渡した」のは、それを認識していようがいまいが、プログラマの書いたコードに基づいた振る舞いなのです。

なので、帳尻が合うように整合を保つのもプログラマの責任ということになります。

これは COM の大原則で、C++ でプログラミングしていても同じことが言えます。


_________________
// 渋木宏明 (Hiroaki SHIBUKI)
// http://hidori.jp/
// Microsoft MVP for Visual C#

[ メッセージ編集済み 編集者: 渋木宏明(ひどり) 編集日時 2006-03-16 12:29 ]
じゃんぬねっと
ぬし
会議室デビュー日: 2004/12/22
投稿数: 7811
お住まい・勤務地: 愛知県名古屋市
投稿日時: 2006-03-16 12:22
引用:

渋木宏明(ひどり)さんの書き込み (2006-03-16 12:07) より:

全てではありません。
実装を確認した訳ではありませんが、1個だけ減らすはずです。


常にそうであるわけではないですよ。
別のスコープで参照を持っているものがいれば「1 個だけ」減らすという動作をします。
それ以外の場合では、すべてデクリメントされます。

# ひどりさんと COM Interop 関係の話をするのは何回目かなぁ (^^)

_________________
C# と VB.NET の入門サイト
じゃんぬねっと日誌
渋木宏明(ひどり)
ぬし
会議室デビュー日: 2004/01/14
投稿数: 1155
お住まい・勤務地: 東京
投稿日時: 2006-03-16 12:32
引用:

じゃんぬねっとさんの書き込み (2006-03-16 12:22) より:
引用:

渋木宏明(ひどり)さんの書き込み (2006-03-16 12:07) より:

全てではありません。
実装を確認した訳ではありませんが、1個だけ減らすはずです。


常にそうであるわけではないですよ。
別のスコープで参照を持っているものがいれば「1 個だけ」減らすという動作をします。
それ以外の場合では、すべてデクリメントされます。



返信元の記事の意味を取り違えてたんで、↑の記述はカットしてしまいました (^^;

引用:

# ひどりさんと COM Interop 関係の話をするのは何回目かなぁ (^^)



もう飽きてきた (^^;

_________________
// 渋木宏明 (Hiroaki SHIBUKI)
// http://hidori.jp/
// Microsoft MVP for Visual C#
//
// @IT会議室 RSS 配信中: http://hidori.jp/rss/atmarkIT/
囚人
ぬし
会議室デビュー日: 2005/08/13
投稿数: 1019
投稿日時: 2006-03-16 13:12
引用:

昨日、どこかにも書きましたが「正常終了時に限り」ですね。
それと、既にリークしている場合がないとも限らなかったり。
↑"そういう" 意味でも自前で参照を取って、責任を持ってしかるべき順番で、
ReleaseComObject していくというのが現状最も安全であると思います。


何かいい方法ないかなぁと思いましたが、ひどりさんの言う COM 側へ渡す問題が存在するなら、そんないい方法はないんですね。

引用:

だから、何でもかんでも ReleaseCOMObject() すればいい、という訳ではないんです。
タイミングは非常に重要です。


引用:

厳密に言えば「COM オブジェクトの参照を別の COM オブジェクトに渡した」のは、それを認識していようがいまいが、プログラマの書いたコードに基づいた振る舞いなのです。

なので、帳尻が合うように整合を保つのもプログラマの責任ということになります。


という事で納得。

COM Interop、少し突っ込んで調べてみようと思いました。

引用:

もう飽きてきた (^^;


すいません。^^;

_________________
囚人のジレンマな日々
nanbu
大ベテラン
会議室デビュー日: 2004/08/19
投稿数: 178
投稿日時: 2006-03-16 15:44
南部です。

結局、単純なデクリメントは既にRCWで実装されているので、
参照をデクリメントする順番を考慮する場合や、
COMオブジェクトの有効期間を明示的に制御する場合以外は、
Marshal.ReleaseComObjectを叩く必要ない、、でいいのかな?
#まあ、RCWのカウンタ下げるだけだし、デストラクタに任せても、、

例になった単純なケースでは、こんな感じ。
コード:
Excel.Application xlApp = new Excel.Application();
try
{
  xlApp.DisplayAlerts = false;
  xlApp.Visible = false;
  
  Excel.Workbook workbook = xlApp.Workbooks.Add(Type.Missing);
  Excel.Worksheet worksheet = (Excel.Worksheet)workbook.Worksheets["Sheet1"];

  ((Excel.Range)worksheet.Cells[1, 1]).Value2 = "COM Interop is hated!";
			
  workbook.SaveAs(
    @"C:\\\\Book1.xls",
    Type.Missing(4個),
   Type.Missing,Excel.XlSaveAsAccessMode.xlExclusive, 
    Type.Missing(5個));
}
finally
{
  xlApp.Quit();
}



引用:

別のスコープで参照を持っているものがいれば「1 個だけ」減らすという動作をします。
それ以外の場合では、すべてデクリメントされます。


もし失念していなければ、これのソースを教えて欲しいのですが。
じゃんぬねっと
ぬし
会議室デビュー日: 2004/12/22
投稿数: 7811
お住まい・勤務地: 愛知県名古屋市
投稿日時: 2006-03-16 16:59
引用:

nanbuさんの書き込み (2006-03-16 15:44) より:

COMオブジェクトの有効期間を明示的に制御する場合以外は、
Marshal.ReleaseComObjectを叩く必要ない、、でいいのかな?
#まあ、RCWのカウンタ下げるだけだし、デストラクタに任せても、、


GC によっていつ解放されるかわからないということは、
異常終了時にはリークしたままになるということを示します。

なので「有効期間を明示的に制御する場合以外」のシナリオがあまり思いつかなかったり... (;^-^)
ユーザーに「はい、どうぞ」という意味であっても必須になるということです。

  VB.NET から EXCELオブジェクトの操作

引用:

もし失念していなければ、これのソースを教えて欲しいのですが。


わーないです、というより多分間違ってます。
1 個というよりは未到達の分、デクリメントしようとする。
1 個でも有効な参照がある場合は、まったくデクリメントされない。
1 個だけという状況はない、が正しいかな。

_________________
C# と VB.NET の入門サイト
じゃんぬねっと日誌

スキルアップ/キャリアアップ(JOB@IT)