- - PR -
[C#] デリゲートをGCの対象から外す方法
1|2|3|4|5
次のページへ»
投稿者 | 投稿内容 | ||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
投稿日時: 2007-01-24 11:40
質問
デリゲートのアドレスが移動しないようにするにはどうすれば良いですか? 例えばGC.KeepAliveメソッドと適切な属性を組み合わせるのでしょうか? 背景 あるボードのデバイスドライバーが初期化時にコールバックメソッドのポインターを渡す仕様になっています。 ボードは初期化されると一定時間毎にコールバックメソッドを呼び出し続けます。 デリゲート経由でコールバックメソッドを呼び出したところ、初期化後しばらくは正常に機能しますが、 やがてWindowsXPをフリーズ(ブルースクリーン)させてしまいます。 デバイスドライバーは初期化時のアドレスが動かないものとして処理しているため、 GCによるデリゲートの移動でボードが誤ったアドレス参照してしまい、ハングアップするものと思われます。 デリゲートがインスタンス化している期間アドレスを固定する方法があるでしょうか? | ||||||||||||
|
投稿日時: 2007-01-24 11:51
・デリゲートインスタンスをフィールドにおいておく
・GCHandle 構造体をフィールドにおく たぶん後者が必要ですが、前者でなんとかなるかもしれません。実験してみていただけたら幸いです。 GC.KeepAlive は、あるメソッド内で回収されるタイミングを遅らせるためだけのものです。 | ||||||||||||
|
投稿日時: 2007-01-24 12:06
GCHandleType.Pinned で GCHandle.Alloc かと思っていたのですが、
がどういった方法を指すのか分からないので、もし宜しければ教えて頂けないでしょうか。 [ メッセージ編集済み 編集者: 囚人 編集日時 2007-01-24 12:31 ] | ||||||||||||
|
投稿日時: 2007-01-24 13:12
単に GC による移動を防ぐだけなら Pinned は不要です。 そもそもプリミティブな型以外を含むオブジェクトには Pinned は不可能だったはずです。
デリゲートのマーシャリングでやりやすいのは、デリゲートオブジェクトをメソッドローカルで作ってしまうことです。 当然、アンマネージドな世界にデリゲート(マーシャリング済みの関数ポインタ)がわたったなんてことはマネージド世界では認識されませんから、メソッドを抜けた時点で到達不能インスタンスになり、GC に片付けられます。 // と言うのは釈迦に説法かと思いますが。 今回のもそれじゃないかなぁと。 フィールドにデリゲートインスタンスを持たせれば、(null を入れない限り)そのオブジェクトが存在している間はデリゲートインスタンスは残りますから、短期的な解決にはなります。 当然これだけでは GC による移動は制限できないわけなので、多分不十分な解決のはずですが。 | ||||||||||||
|
投稿日時: 2007-01-25 07:55
なるほど。そういう事だったのですね。ありがとうございます。となるとアドレスが移動してしまうのは避けようがないんですね。 [ メッセージ編集済み 編集者: 囚人 編集日時 2007-01-25 07:57 ] | ||||||||||||
|
投稿日時: 2007-01-25 12:00
あれー? アンマネージドに渡したデリゲートがマネージ側で参照を維持してないとGCで片付けられてしまう、というのは MSDN のどこかに注意書きがあったはずです。 ですが、マネージ側でデリゲートの参照を維持している限り、デリゲートのアドレスが変わったりはしないんじゃないですかね??? 移動する前提に立つと、アンマネージにデリゲートを渡すこと自体そもそも無意味な行為になってしまいませんか? | ||||||||||||
|
投稿日時: 2007-01-25 12:23
こんにちは。
デリゲートのアドレスがGCによって移動させられることがあるのであれば、 .NET Framework内部はどう対処しているのでしょう? 逆アセンブルすると、以下のようなネイティブへ引き渡されるデリゲートがたくさん定義されているのですが。
なにかアドレスを固定しておく方法がないと、おかしくないでしょうか。 | ||||||||||||
|
投稿日時: 2007-01-25 13:13
なんとなく想像で考えると、デリゲートのマーシャリングは、
・デリゲートが示すコールバックを代わりに受け取るメソッドスタブを生成する ・ネイティブコードには上記スタブのアドレスを渡す ・スタブは、対象となるデリゲートを保持していて、デリゲートにデリゲートする という感じな気もしますが… これだとスタブがいつ掃除されるのか微妙ですね… ※アンマネージから戻ったあとで掃除してしまうと、 使われ続けるかもしれないコールバックを破壊してしまうし… まあ、少なくともデリゲートインスタンスが固定されている必要はないわけで。 ※固定されている必要があるのは、アンマネージの世界から直接呼び出される メソッド実体のアドレスであって、デリゲートインスタンスではない、と 上記は単なる想像であって、実際どういう仕組みになってるのかは知りません。 |
1|2|3|4|5
次のページへ»