掲示板システム
ホーム
アクセス解析
カテゴリ
ログアウト
VB.net DLLのメモリリークについて (ID:143367)
名前
ホームページ(ブログ、Twitterなど)のURL (省略可)
本文
> メモリは開放されるものと 開放は、自身が管理している資源を、他者にも利用できるよう開け放つ(free/open)こと。 解放は、自身が管理していた資源を解き放ち、自身の管理権を破棄する(dispose)こと。 学校の図書館を一般カイホウするのは前者、捕虜をカイホウするのは後者ですが、 メモリについてはどちらの意味でも使われるので、使い分けに注意が必要ですね。 閑話休題。 まず、シロさんの方で、問題個所の切り分けは出来ていますか? たとえば、 (1) COM 化することなく、単に Ping.SendAsync を繰り返した場合 (2) 何もしない DLL を作り、それをVB6から繰り返し呼び出した場合 (3) Ping クラスを生成するだけで、SendAsnyc を呼ばなかった場合 (4) WM_USER_PING メッセージ交換のみで Ping を実行しない DLL とした場合 などといった判定作業です。(他にも検討すべき個所はあるかもしれません) 先の私の回答は、上記(1)に対するものだけであり、それ以外の 要因には触れていません。もしも複合的な要因であった場合、 IDisposable.Dispose だけでは解決しない可能性があります。 さて、そもそもの Ping.SendAsnyc のメモリリーク問題については、 下記を参照してみてください。 http://blog.mbcharbonneau.com/2006/11/14/using-the-ping-class-in-net-20-without-memory-leaks/ http://blogs.msdn.com/b/joncole/archive/2005/12/15/debugging-a-memory-leak-in-managed-code_3a00_-ping-_2d00_-sendasync.aspx .NET 2.0〜3.5 の Ping クラスは、Component クラスを継承しているのですが、 Dispose(Boolean)がオーバーライドされていないため、Ping.Dispose() を呼び出しても、 単にベースクラスの Component.Dispose() が呼ばれるだけとなり、Ping クラスの 内部リソースには影響を与えないという問題があります。そもため VB2008 から 意図的に「IDisposable の」Dispose を呼び出す必要があるということです。 なお、.NET 4 以降の Ping クラスは、Component.Dispose(Boolean) メソッドが オーバーライドされているため、Ping.Dispose() メソッドの呼び出しだけで 問題ないと思います。個人的な予想であって、検証したわけでは無いですけれどね。 > DirectCastはどこにいれるのが正解でしょうか? IDisposable.Dispose すべきは、オブジェクトの使用後です。 つまり、少なくとも Ping 完了後に実施されるようにしておいてください。 作成された DLL は イベントを公開していないようなので、 PingCompleted イベントを抜けた後のタイミングが適切では無いでしょうか。 > Disposeの代わりに下記の通り追加してみました。 SendAsnyc 処理中に破棄しては、流石にマズイでしょう。 > 逆にPingCompletedの最後にDirectCastの処理を入れるとVB6側のソフトが落ちました。 それは、実行時にトラップ可能なエラーでしょうか。また、どの行で落ちたのでしょうか。 現時点の情報だけでは、VB6 に何が起きたのかを私には想像できないのですが、とりあえず (案1) VB6 側が、受信完了後に Dispose 発行依頼のメソッドを呼び出す形に修正する。 (案2) Timer 等を併用し、PingCompleted イベント完了後に Dispose する形にする。 などと修正してみるのは如何でしょうか。 その上で、DLL 側(Netchk クラス)を IDisposable パターンで 実装しておく必要もあるでしょう。理由については後述します。 http://msdn.microsoft.com/ja-jp/library/s9bwddyx%28v=vs.80%29.aspx > Nothingをした時点でメモリは開放されるものと思っていたのですがなかなかうまくいかないですね。 そもそも、VB6 側での Nothing 代入は不要です。 今回のコードでは obj がローカル変数となっているため、何もせずとも 変数がスコープ外になった時点で、自動的に参照カウントが減じられます。 また、Nothing 代入も End Sub の直前にあるのみなので、早期解放の 意図ともなっておらず、この時点での Nothing 代入自体にはあまり意味がありません。 それはさておき、VB6 側参照カウントがゼロになった時点で、 ActiveX オブジェクトの終了処理は完了します。ただし、 ここで破棄されるのは COM が使用しているリソースだけです。 もちろんそこから付随して、COM 呼び出し可能ラッパー(CCW)によって、 .NET 側のマネージ オブジェクトの参照も自動的に解放されます。 ただしそれは、あくまでも「マネージオブジェクト」に対してのみであり、 Ping クラスのようにアンマネージなオブジェクトの場合、解放処理は 開発者自身が手動で破棄せねばなりません。 とはいえ多くのマネージオブジェクトは、プログラマが Dispose 等の終了処理を呼び出し忘れていたとしても、GC 回収時に 終了処理が自動的に施され、アンマネージリソース等(今回の場合で言えば、 IcmpCreateFile API のハンドルなど)のリークが起きないよう 設計されています。(たとえば IcmpCloseHandle 等を呼び出すなど) ところが .NET 3.5 以下では、先述した理由によって、Ping.Dispose が 実質機能していないため、IDisposable.Dispose の明示的実行が 必要となります。 しかも、Component が正しく実装されていませんし、かといって Ping クラスに Finalize が明示実装されているわけでもありません。 そのため、GC 回収時にアンマネージリソースの後始末が自動的に 実施されることも無さそうなので、Ping を呼び出す自作クラス自体も、 IDisposable インターフェイスを実装するなどの対策が必要でしょう。
←解決時は質問者本人がここをチェックしてください。
戻る
掲示板システム
Copyright 2020 Takeshi Okamoto All Rights Reserved.