DOBON.NET DOBON.NETプログラミング掲示板過去ログ

FormのCloseでリーク?

環境/言語:[NET Framework 1.1 VB.NET2003 OS:WinXP]
分類:[.NET]

宜しくお願いいたします。こうといいます。
現在 Formの基底クラスを作りそれを継承してFormを作り(Form2とします)
親フォーム(Form1とします)からShowDaialogで表示させています。
(MDIアプリです)
Form1もForm2と同じFormを継承元としています。
Form2では DataTableのColumnChengingイベントでデータ変化時の処理をしています。
実際にはDataGridでDataTableの内容を表示し、キー入力でカラムの内容が変わったときの処をしたくてDataTableのColumnChengingイベントを使用しています。

長くなりましたが
何度もForm2を開いたり閉じたりしていると1回のカラムの変更がForm2を開いた回数分発生してしまうのです。
ColumnChengingでブレークを貼り、そのときのMe.Handleをみていると、どうやらForm_CloseではFormのClassが開放されていないような動作をしているのです。(Handleが今まで開いたときの値にブレークで止まる度に変わる)

結局どうしたいかと言うと
FormのCloseでForm2がきれいに開放できれば良いとおもっています。
(ColumnChengingは1回しか発生しないようにしたい)
Form2を開く方法は
dim NewForm as Form2
NewForm = New Form2( XX ) <--コンストラクタを作っています
NewForm.showdaialog
とこんな感じです。

だらだらと書いて申し訳ありませんが
上記内容について情報をいただきたいと思い投稿いたしました。
宜しくお願いいたします。
自己レスです

下記コードについて
> dim NewForm as Form2
> NewForm = New Form2
> NewForm.showdaialog

色々と過去ログ等で調べました。
そこで分かったことは、
1.NewForm.showdaialog
  の後はNewForm.Dispose() をしないとインスタンスは残ってしまうと言うこと
2.DataTableのイベントは WithEvents dt as DataTableでやっているが
  Form2のCloseイベントにて dt = Nothingをしてあげないと
  Disposeをしても残ってしまい(ここがよく分からないが)イベントが発生してしまう
3.NewForm.Dispose() をしても タスクマネージャ等でみているとメモリがリークしているように見えるが、リークしているわけではないこと
ガベージコレクションの対象になりいつかは解放されると言うこと

上記3点、かなり自信がありませんが、間違っていれば指摘して下さい
宜しくお願いします。

上記3点がなんとなくわかった
お察しのとおり、インスタンスはどこからも参照されなくなってもガベージコレクタによって回収されるまで有効です。したがって、Form2のインスタンスが作成されるたびにColumnChengingにメソッドを結びつけ、破棄されるまで結び付けられたままになります。複数のForm2が作成されるとColumnChengingにはそれぞれのメソッドが結びついた状態になるため、イベントが発生すれば結び付けられた複数のメソッドが呼び出されることになります。

この状態についての対策としてはいくつかあります。

1.GC.Collectメソッド
GC.Collectメソッドを使用して強制的にガベージコレクタに使用しないメモリを回収させます。とはいえまだどこかから参照されている場合には回収されないため、確実に参照されていないようにする必要があります。こうした手法はガベージコレクタの利点を半減させてしまうため(従来どおり手動でメモリ開放をしているようなものです)、あまりよくないかもしれません。

2.Form2を再利用する
Form2のインスタンスが常に1つしか存在しない設計であれば毎回Form2のインスタンスを作成するのではなく、一度作成したインスタンスをフィールドなどのように保持してそれを再利用するという方法があります。この方法はメモリの節約もできそうですが、Form2のインスタンスを複数存在できるような仕様への変更があった場合には問題になります。

3.AddHandler,RemoveHandler
WithEventsの代わりにAddHandlerでメソッドを結びつけ、処理が終わったときにRemoveHandlerで結びつけたメソッドを開放します。GC.Collectよりは確実に処理が可能です。
Codingslaveさんありがとうございます。

だいたい、私の調べた通りで少し安心です。
3番のことでもう少し教えて下さい
> 3.AddHandler,RemoveHandler
> WithEventsの代わりにAddHandlerでメソッドを結びつけ、処理が終わったときにRemoveHandlerで結びつけたメソッドを開放します。GC.Collectよりは確実に処理が可能です。

の方法ですが
WithEvents dt as DataTable
dt = Nothing
でNothingにするのでは、ダメなのでしょうか
動きはイベントが発生しなくなり
理想の形になったのですが..
WithEvents を使用しているところがかなりあるので
AddHandlerに変更するのは大変です。
Closeイベントで dt = Nothing
にするだけだと簡単に修正が可能なのですが
ここの点も教えてくだされば、幸いです。
宜しくお願いします。
調べてみたところ、どうやらNothingの代入で問題がないようです。

VBはWithEventsが指定されたフィールドを、内部でsetとgetアクセサを持つプロパティに変換しているようです。
このプロパティのsetアクセサの中では、AddHandlerとRemoveHandlerが使用されていて、すでに設定された値のイベントの設定や解除を行っているようですが、このときにNothingが代入されるとイベントは解除された状態になります。
Codingslaveさんへ
> VBはWithEventsが指定されたフィールドを、内部でsetとgetアクセサを持つプロパティに変換しているようです。
> このプロパティのsetアクセサの中では、AddHandlerとRemoveHandlerが使用されていて、すでに設定された値のイベントの設定や解除を行っているようですが、このときにNothingが代入されるとイベントは解除された状態になります。

ありがとうございます
=Nothingで切り抜けそうです

VB6は経験があるのですが
.NETでは色々と調べることがありますね
これからも.NETのスキルをあげていきたいとおもいます。
では失礼します。
解決済み!

DOBON.NET | プログラミング道 | プログラミング掲示板