- PR -

継承したコントロールのメモリの解放

投稿者投稿内容
KT工房
常連さん
会議室デビュー日: 2006/06/20
投稿数: 49
投稿日時: 2009-01-20 13:47
いつもお世話になっております。
現在 VisualStudio.Net2005 の VB にて開発しています。

アプリを組み終わり実行しているとメモリリーク?の現象が出ました。
どこかで解放忘れがあるのかと思い、調べていたところ
データセット(新規追加で作成できるデータセットです)のインスタンスを生成して、
解放しているつもりなのですが、そのメモリが解放されていない?ことが原因のようです。

さらに調べていくと、継承したコントロールでも同様の現象が確認できました。

以下にミニマムコードを記述しておきます。

******************************************************************************


'単純にDataSetを継承しただけのカスタムDataSet
Public Class CustomDataSet
Inherits DataSet
End Class

'単純にLabelを継承しただけのカスタムLabel
Public Class CustomLabel
Inherits Label
End Class

'ボタンによりテスト実行
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click

Debug.WriteLine(String.Format("{0:HH:mm:ss.fff} Start [{1:0}]", Now, GC.GetTotalMemory(False)))

'テスト的にループさせて生成→解放する
For i As Integer = 0 To 1000000

'[ カスタムDataSetの場合 ] *************************************
Dim xLeak As CustomDataSet

xLeak = New CustomDataSet
xLeak.Dispose()
xLeak = Nothing


''[ カスタムLabelの場合 ] ************************************
'Dim xLeak As CustomLabel

'xLeak = New CustomLabel
'xLeak.Dispose()
'xLeak = Nothing


''[ 通常のDataSetの場合 ] ************************************
'Dim xNoLeak As DataSet

'xNoLeak = New DataSet
'xNoLeak.Dispose()
'xNoLeak = Nothing


''[ 通常のLabelの場合 ] ************************************
'Dim xNoLeak As Label

'xNoLeak = New Label
'xNoLeak.Dispose()
'xNoLeak = Nothing

Next

Debug.WriteLine(String.Format("{0:HH:mm:ss.fff} Before GC.Collect [{1:0}]", Now, GC.GetTotalMemory(False)))

GC.Collect()

Debug.WriteLine(String.Format("{0:HH:mm:ss.fff} End (GC.Collect) [{1:0}]", Now, GC.GetTotalMemory(True)))

End Sub

******************************************************************************


継承したコントロールの解放には何か特別な処理などが必要なのでしょうか?
もしくは私のPCだけで起きる現象なのでしょうか?

ちなみに VisualStudio.Net2003 で上記ミニマムコードを実行しても
メモリは増えませんでした。

難しいかも知れませんが、よろしくお願いします。

囚人
ぬし
会議室デビュー日: 2005/08/13
投稿数: 1019
投稿日時: 2009-01-20 14:28
メモリが増えた減ったの判定はどうやってますか?
KT工房
常連さん
会議室デビュー日: 2006/06/20
投稿数: 49
投稿日時: 2009-01-20 14:40
ミニマムコード内の Debug.WriteLine にて出力しているもので判定しているのですが・・・。
逆にこれでは判断できないのでしょうか?
囚人
ぬし
会議室デビュー日: 2005/08/13
投稿数: 1019
投稿日時: 2009-01-20 14:51
すみません。判定に何かツールを使ってると思い込んでいたのでコードをちゃんと読んでいませんでした。

もし、Dispose を呼び出したり、Nothong を代入することで、GCが実行されると考えられている場合は、これは違います。
また、GC.Collectを呼び出した場合は、確かにGCが実行されるのですが、これまたすぐに実行されるかどうかと言えば、CLRの気分次第です。
たとえば複数のプロセッサを使用していて、サーバー版CLRを使用していた場合は「真に併行」してGCが実行されたりします(確か)。
なので、そういうチェックはしないで、「GCをとりあえず盲信する」てのが一般的な落ち着きどころかと。

KT工房
常連さん
会議室デビュー日: 2006/06/20
投稿数: 49
投稿日時: 2009-01-20 15:06
コメントありがとうございます。

GCをとりあえず盲信しているのですが、いつまでたっても解放されないため。
OutOfMemoryException でお亡くなりになってしまいます。
ミニマムコードのループ件数を2桁ほど増やせば落ちてくれます。

VS2005からCLRの気分がよろしくないのでしょうかね(笑)

単純にControlを継承しただけでもダメでした。
標準コントロールのLabelなんかもColtrolを継承しているはずなのに、
こちらは現象が起こりません。
なにかがありそうな気がするのですが・・・。
Tdnr_Sym
ぬし
会議室デビュー日: 2005/09/13
投稿数: 464
お住まい・勤務地: 明石・神戸
投稿日時: 2009-01-20 15:28
こんにちは。

引用:

KT工房さんの書き込み (2009-01-20 15:06) より:

GCをとりあえず盲信しているのですが、いつまでたっても解放されないため。
OutOfMemoryException でお亡くなりになってしまいます。



DataSetの継承元のSystem.ComponentModel.MarshalByValueComponentクラスが
ファイナライザを実装しているようですね。
だからGCで回収されにくくなっているんじゃないでしょうか?

「参考」
ガベージ コレクタの基本とパフォーマンスのヒント (ファイナライゼーションがガベージ コレクションに与える影響)
ガベージコレクション入門: Microsoft .NET Framework の自動メモリ管理 Part I (完結化の内部メカニズム)
Tdnr_Sym
ぬし
会議室デビュー日: 2005/09/13
投稿数: 464
お住まい・勤務地: 明石・神戸
投稿日時: 2009-01-20 15:48
引用:

Tdnr_Symの書き込み (2009-01-20 15:28) より:
DataSetの継承元のSystem.ComponentModel.MarshalByValueComponentクラスが
ファイナライザを実装しているようですね。
だからGCで回収されにくくなっているんじゃないでしょうか?



いや違ったかもしれません?
MarshalByValueComponent.Dispose内で、GC.SuppressFinalize メソッドを呼び出しているようなので
完結キューにはエントリされないのかも!?
KT工房
常連さん
会議室デビュー日: 2006/06/20
投稿数: 49
投稿日時: 2009-01-20 15:56
Tdnr_Symさんコメントありがとうございます。

ファイナライザの実装により、解放タイミングに違いが生じるということを
知らなかったので大変勉強になりました。

ですが、DataSetのほうはすぐに解放されるのに対し、
単純に継承したDataSetはすぐに解放されないというのは納得できません。

Tdnr_Symさんは継承元のソースを見られているようですが、
どこかで公開されているのでしょうか?

スキルアップ/キャリアアップ(JOB@IT)