- - PR -
[C#] デリゲートをGCの対象から外す方法
投稿者 | 投稿内容 | ||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
投稿日時: 2007-01-25 13:20
あらためて GCHandleType.Normal の解説を読むと、いまいち必然性が理解できなくなりました。 Alloc(object, GCHandleType.Normal) で GCHandle を確保した場合、固定はされないので動き得る。効果は GC の対象にならないってだけ。でも結局 GCHandle オブジェクトを残しておかない限り Free を呼び出すタイミングは失われるわけで、結局いずれ解放するためにはどこかのフィールドに残す必要がある。となると直接オブジェクトの参照を残せばいい話で、敢えて GCHandle をはさむ必要は一体どこにあるんだろう? とかなんとか。メソッド内で GC させたくないのなら GC.KeepAlive で良いし。 実のところ GCHandle.Alloc さえしてやれば GC の移動の対象からも外されると思い込んでいたんですよねぇ。 MSDN の相互運用マーシャリングにも詳しい解説は無し。フィールドにデリゲートインスタンス置いとけば? 程度。 Marshal.GetFunctionPointerForDelegate メソッドの解説にも、GC の収集については注意していますが移動については触れられていません。 C++/CLI のサンプルコードにはメソッド内で GCHandle.Alloc(delegate)/Free を呼び出したりしてるのもあったり。 // .NET Framework アーキテクトのブログとかに情報があったりするのかしらん? 印象としては、デリゲートインスタンスをフィールドに置いてさえおけば問題なくやってくれるっぽいんですけど。 移動する前提に立つと色々難しい問題が出てきますしねー。 | ||||||||||||
|
投稿日時: 2007-01-25 13:23
なんとなくさんこうになりそうな…
CallbackOnCollectedDelegate http://msdn.microsoft.com/msdnmag/issues/06/05/bugbash/default.aspx#S3 | ||||||||||||
|
投稿日時: 2007-01-25 13:26
ここにデリゲートをマーシャリングする例があります。
http://msdn2.microsoft.com/ja-jp/library/ektebyzx(VS.80).aspx (C++/CLIの例なのでpin_ptr<>を使っていますけど) なちゃさんが >固定されている必要があるのは、アンマネージの世界から直接呼び出されるメソッド実体のアドレス と書かれていますが、これを見るとデリゲートインスタンスをピンで留めてるんですよね。 デリゲートで参照されている限りは、その参照されているメソッド実体のアドレスは移動しないというルールがCLIの仕様にあるんでしょうか。 [ メッセージ編集済み 編集者: 一郎 編集日時 2007-01-25 13:39 ] | ||||||||||||
|
投稿日時: 2007-01-25 13:29
こんにちは。
実は私もそんな想像をしていました。 アンマネージで必要なのは、 メソッドのアドレスであって、デリゲートインスタンスではないよなぁと考えていました。 | ||||||||||||
|
投稿日時: 2007-01-25 13:35
pin_ptrはローカル変数としてしかもてないので、 そのブロックを抜けてもコールバックされるような関数(たとえばSetTimerとか) では使えないっぽいです。 半年ほど前ですが、SetTimerをC++/CLIで使う例を書きました。 C++/CLIなんだから別にデリゲードを使わなくでも出来るんですけどね。。。 http://hpcgi1.nifty.com/MADIA/Vcbbs/wwwlng.cgi?print+200606/06060058.txt あっているか自信はないです。 | ||||||||||||
|
投稿日時: 2007-01-25 14:48
こんにちは。
ここのソースを眺めているのですが、 http://www.microsoft.com/downloads/details.aspx?FamilyId=3A1C93FA-7462-47D0-8E56-8DD34C6292F0&displaylang=en#filelist デリゲートマーシャラの実装はこの辺なんでしょうかね? sscli/clr/src/vm/marshaler.h(3485):
sscli/clr/src/vm/comdelegate.cpp(374):
うーん、C++erな私でも ソースがまったく理解できません(-_-;) (Java6VMのソースもそうでしたが…) | ||||||||||||
|
投稿日時: 2007-01-25 15:18
こんにちは。
先ほどのソースで…
デリゲートからアンマネージコールバックを取り出す間だけは デリゲートインスタンスをGCから保護しているようですが、 コールバックを取り出したら、デリゲートインスタンスは保護する必要がないように見えます。 | ||||||||||||
|
投稿日時: 2007-01-26 10:01
そうそう、もちろんそのつもりで議論してたつもりです。 そのつもりで書いてましたが、
は読み返すとそーでもなく読めてしまいますね。ごめんなさい。 で、元々このスレッドで問題にしていたコトは、アンマネージ側に渡ったコールバックアドレスがいつまで有効なのか?ということだったはずです。 (いつのまにか「何が」固定されているのか、に流れてしまいましたが) それに関して、少なくともマネージ側でデリゲートインスタンスの参照が有効な間は、常にデリゲートに渡されたメソッドを呼び出すはず、というのが僕の主張です。 (なので、元質問者の人が書いているような状況は本来は起きないはずで、起きているとしたら何か原因があるはず) 一度設定したコールバックアドレスが何度も呼び出されるなんてコトは Windows API の世界では日常茶目仕事(既に上がっていますが、代表例が WndProc)な訳で、そういうつくりになってないと何事も立ち行かなくなってしまいます。 [ メッセージ編集済み 編集者: 渋木宏明(ひどり) 編集日時 2007-01-26 10:07 ] [ メッセージ編集済み 編集者: 渋木宏明(ひどり) 編集日時 2007-01-26 10:08 ] |