BT

新しい あなたは、アーリーアダプター?それともイノベーター?そんな皆様に、InfoQの新機能をご案内しています。詳細はこちら

Marshal.ReleaseComObjectは危険な場合がある

| 作者: Abel Avram フォローする 4 人のフォロワー , 翻訳者 尾崎 義尚 フォローする 0 人のフォロワー 投稿日 2010年3月26日. 推定読書時間: 1分未満 |

原文(投稿日:2010/03/19)へのリンク

Visual StudioプラットフォームチームのプリンシパルデベロッパのPaul Harrington氏は、マネージドコードからCOMオブジェクトを破棄するためにMarshal.ReleaseComObject()を呼び出すことが、なぜ危険であり、推奨されていないかについて解説した。

Harrington氏は、Visual 2010のいくつかのコンポーネント、ウィンドウマネージャ、コマンドバー、テキストエディタをネイティブコードからマネージドコードに変更しているとき、Marshal.ReleaseComObjectを使用した問題に気づいた。VS 2005と2008のコンポーネントは、ネイティブコードで書かれており、それらをマネージドコードに移植するまでは、正常に動作していた。

マネージドコードが、COMの機能を呼び出すとき、COM 相互運用(Interop)を経由する。COMオブジェクトを呼び出すとき、CLRからランタイム呼び出しラッパ(RCW:Runtime Callable Wrapper)にラップされた、マネージドオブジェクトのルールに従ったオブジェクトが返され、ガベージコレクション(GC)の対象になる。これはRCWは、GCが動作するタイミングにクリーニングされ、アプリケーションが多くのリソースを使用しない場合、GCの実行がかなり遅延されるか、アプリケーションが終了するまで実施されない可能性があることを意味する。RCWが大きなCOMオブジェクトを保持して、GCが実行されないままアプリケーションが終了された場合、それがリークするという既存のリスクが存在する。

破棄されていないCOMオブジェクトが残るのを避けるために、COM相互運用には、いくつのクライアントがオブジェクトを呼び出しているかをカウントするRCWの参照カウンタを減少させるMarshal.ReleaseComObjectメソッドが提供されている。メソッドは、参照数の新しい値を返すが、「ランタイム呼出可能ラッパーがCOMオブジェクトをラップしたものを呼び出しているマネージドクライアントはひとつだけであるため、 通常はゼロ である」。そのとき、COMオブジェクトによって使用されている隠れたリソースは、解放されるべきである。

この仕組みは、以前のバージョンのVisual Studioでは、Marshal.ReleaseComObjectを呼び出しても問題なく動作していた。しかし、いくつかのコンポーネントがマネージドコードで書き直された時にそうではなくなった。新しいコンポーネントは、互換性を保つために相互互換レイヤであるCOM呼出可能ラッパ(CCW:COM Callable Wrapper)を経由してアクセスされる。そのため呼出側は、それがネイティブCOMオブジェクトであると考えるが、それは実際にはマネージドである。本来はCOMリソースを解放するという意味のMarshal.ReleaseComObjectが呼び出されるまではすべてうまく動作する。解放しようとしているオブジェクトがCOMではなく、マネージドのため、ランタイムは「オブジェクトの型は、__ComObjectか__ComObjectを継承したものである必要があります。」というメッセージとともにArgumentExceptionをスローする。

今のところMarshal.ReleaseComObjectを使った他の問題は存在しない。通常、メソッドを呼び出したときには、COMリソースがリリースされ、0が返される。これは、COMオブジェクトがRCWラッパーから解放されたことを意味する。もし、オブジェクトがガベージコレクトされておらずにキャッシュされている状態で、他のクライアントが同じCOMオブジェクトを呼び出した場合、「COMオブジェクトは、すでにRCWから解放されているため使用できません。」というメッセージとともにInvalidComObjectExceptionがスローされる。そのため、Marshal.ReleaseComObjectは、そのCOMオブジェクトを確実に使わないとわかった時点で呼び出す必要がある。

VS2010の問題を解決するためにチームは、すべてのMarshal.ReleaseComObjectの呼びだしを削除して、それを使用しないことを推奨した。彼らは、「VS2005とVS2008のManaged Package Frameworkにパッチを適用し、VS 2010から呼び出されたときにReleaseComObject問題が発生しないようにしたバージョンを作成した。パッチが適用されたバージョンは、“devenv.exe.config”でMicrosoft.VisualStudio.ShellとMicrosoft.VisualStudio.Shell.9.0のバインドがリダイレクトされていることを確認することができる」。この問題は、VS 2010上で、COM相互運用をしているプロジェクトでは、一般的な問題になる可能性がある。

この記事に星をつける

おすすめ度
スタイル

こんにちは

コメントするには InfoQアカウントの登録 または が必要です。InfoQ に登録するとさまざまなことができます。

アカウント登録をしてInfoQをお楽しみください。

あなたの意見をお聞かせください。

HTML: a,b,br,blockquote,i,li,pre,u,ul,p

このスレッドのメッセージについてEmailでリプライする
コミュニティコメント

HTML: a,b,br,blockquote,i,li,pre,u,ul,p

このスレッドのメッセージについてEmailでリプライする

HTML: a,b,br,blockquote,i,li,pre,u,ul,p

このスレッドのメッセージについてEmailでリプライする

ディスカッション

InfoQにログインし新機能を利用する


パスワードを忘れた方はこちらへ

Follow

お気に入りのトピックや著者をフォローする

業界やサイト内で一番重要な見出しを閲覧する

Like

より多いシグナル、より少ないノイズ

お気に入りのトピックと著者を選択して自分のフィードを作る

Notifications

最新情報をすぐ手に入れるようにしよう

通知設定をして、お気に入りコンテンツを見逃さないようにしよう!

BT