- - PR -
[C#] デリゲートをGCの対象から外す方法
投稿者 | 投稿内容 | ||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
投稿日時: 2007-01-26 19:24
常に1対1対応するものではない、と「されています」。
yield return, yield break のことです。 これらは列挙子オブジェクトの実装を助けるものですが、スタックを積極的に摩り替えることで実現されているはずです。 追記: マネージコードだから、「スタックを操作」と言うよりは「実行コンテキストを積極的に操作して」の方がいいのかな? [ メッセージ編集済み 編集者: 渋木宏明(ひどり) 編集日時 2007-01-26 20:44 ] | ||||||||||||||||
|
投稿日時: 2007-01-26 23:43
# 用語の説明だけですが
thunk というのは, A -> B と直接呼ぶのでなく, A -> thunk -> B のように indirection (間接操作?) を実現するための コードのことをいいます。 リンク先の説明が正しければ,thunk は, 相互運用マーシャラがネイティブ向けに用意したもので, ネイティブ側は,サンクへのポインタ(a pointer to thunk)を 実際のメソッドへのポインタの代わりに受け取って呼んでいて, thunk が実際のCallback用のメソッドを呼んでいる という形になってるようです。 で, delegateのインスタンスが回収される時に, thunkもネイティブ側で相互運用マーシャラによって破棄される という意味でしょう。 追記: -------------------------------------------------------------------- その理屈からすると... Callback用のメソッドを実装するものを sink object というのだけど, その sink object の寿命 と delegeteインスタンスの寿命 を一致させるため, そのsink objectのフィールドメンバに,delegateを加えておいて, デリゲートのインスタンスを一旦それに入れておいてから登録するだけでいいような。 (sink object自体が,回収されないようにしないといけませんが) NativeWindowクラスも MulticastDelegateから派生した WndProcデリゲート クラス 型の windowProc という名前のフィールドをメンバとして持ってるので, 探せば同じようにやってるんじゃないかと。(WindowClass::RegisterClassあたりで) それ以上のことは,必要ないような気がするんですけどね。 [ メッセージ編集済み 編集者: 稍丼 編集日時 2007-01-27 02:02 ] | ||||||||||||||||
|
投稿日時: 2007-01-27 09:34
皆さんご回答ありがとうございます。
私も記事を参考に検索を試みていますが、解決できていません。 (固定アドレスを前提にした)アンマネージなコールバックメソッドに対する 対処方法がどこかにきっと記載されているはずですが、 見つける事ができません。 | ||||||||||||||||
|
投稿日時: 2007-01-27 10:54
もう一度、正確な状況を教えてください。 アンマネージに渡されたコールバックアドレスが、いつの間にか無効になっているということなんでしょうか? であれば、マネージ側の実装が正しければ、そんなことは起きないはずです。 そんなことが容易に起きるとすれば、Windows Forms は成立しません。 「マネージ側の実装が正しい」とは、この場合「アンマネージに渡したデリゲートの参照をマネージ側で保持している」ことを指します。 | ||||||||||||||||
|
投稿日時: 2007-01-27 10:57
サンクもスタブもプロキシも、大雑把に言えばみんな似たようなモンですね。
ある層から別な層を呼び出す時の「踏み台」みたいなもん、でいいのかな? | ||||||||||||||||
|
投稿日時: 2007-01-27 21:33
なるほど!非常に勉強になりました。 何故そんな実装になっているのか疑問なんですけど、Callback用の メソッドがまだ一度も実行されていなかったら(つまり JIT コンパイルされていなかったら)メソッドのアドレスが不定(まだスタブのアドレス)だからなんでしょうか。サンクを通すようにすれば、コンパイルされていなくてもされていても、アンマネージ側は同じアドレスで呼び出せるからとか。 で、最初の問題なのですが、やはりデリゲートインスタンスが途中で破棄されているから? _________________ 囚人のジレンマな日々 | ||||||||||||||||
|
投稿日時: 2007-01-27 23:21
デリゲートが,
とあるとすると,(C/C++的に)いわゆる関数ポインタに
のように名前をつけた感じのような気になるので, 単なる関数ポインタならば, ネイティブ側に直接渡せそうな気がします。 ですが, (CLR via C# (プログラミングMicrosoft .NET Framework第2版) の Chapter 15 にあるように) 実際は,コンパイラが
のような感じでクラスを自動生成してくれています。 メソッドを複数登録して呼び出せるように, マルチキャストデリゲートは, デリゲートのインスタンスがリスト繋がりになれる関係で, メソッドを呼び出すといっても, デリゲートのInvokeメソッド経由で呼び出さないといけないだろうから, > thunk が実際のCallback用のメソッドを呼んでいる は,正確には, thunk が, コンパイラが生成するSystem.MulticastDelegateを継承した (実際のCallback用のメソッドポインタをコンストラクタで受け取り, ラップする形になっている)(デリゲートの)クラスの インスタンスのInvokeメソッドを,呼んでいる になっていると思います。
[ メッセージ編集済み 編集者: 稍丼 編集日時 2007-01-28 01:11 ] | ||||||||||||||||
|
投稿日時: 2007-01-28 02:19
こんばんは。
皆さんマネージな世界にお詳しいですねぇ〜 私はやっぱりドキュメントを読むより、 ソースコードを読んで理解するほうが好きなので… (公式ドキュメントのほうが正しい仕様なのは分かっていますが)
古いソースのほう見ていたようなので 新しいバージョンのほうを見ることにしました。 Shared Source Common Language Infrastructure 2.0 Release いろいろソースを眺めましたが結局 サンクがどのタイミングで破棄されるのか見つけられませんでした。 でも、下記のように(大雑把ですが) デリゲートインスタンス(Object)にサンク(UMEntryThunk)が紐づいている(包含している)のをみると やっぱりデリゲートインスタンスとサンクの寿命は同じな気がします。 皆さんの仰るとおり、デリゲートインスタンスは破棄されないようにしないといけないように思います。
で、サンク(UMEntryThunk,UMEntryThunkCode...)の中身ですが、 バイナリな世界で良く分かりませんでした。 JITコンパイルされたメソッドのアドレス、またはスタブのアドレスを サンクが間接的に公開しているのではないかと想像しているのですが。 ところで… System.Delegateクラスの中身を見ていると
_methodPtr,_methodPtrAuxってどんなポインタが入っているのだろうと気になったのですが… リフレクションで値が見れるのかなぁ? |