2009年6月4日木曜日

.NET(Mobile) アプリのメモリ使用量について

CompactFrameworkアプリでフォームを開いたり閉じたりしていると、メモリ使用量がどんどん増えていきます。

Microsofrフィードバックによると
Inherits Componentしているコントロール(Timer、ToolTipなど)を使用する際に.Netが自動生成するコードが
CompactFrameworkでは自動生成されないためフォームの参照が解放されず、ガーベッジに収集されないらしいのです。

具体的にはCompactFrameworkのMainMenuコントロールはInherits Componentされているにもかかわらず、Desiner.vbでcomponentsに追加されずfinalizaで解放されないということです。
このコードの★部分が本来ならmainMenu1 = New System.Windows.Forms.Mainmenu(components)となる。
 _
Partial Public Class Form1
Inherits System.Windows.Forms.Form

'フォームがコンポーネントの一覧をクリーンアップするために dispose をオーバーライドします。
 _
Protected Overrides Sub Dispose(ByVal disposing As Boolean)
If disposing AndAlso components IsNot Nothing Then
components.Dispose()
End If
MyBase.Dispose(disposing)
End Sub

'Windows フォーム デザイナで必要です。
Private components As System.ComponentModel.IContainer
Private mainMenu1 As System.Windows.Forms.MainMenu

'メモ: 以下のプロシージャは Windows フォーム デザイナで必要です。
'Windows フォーム デザイナを使用して変更できます。  
'コード エディタを使って変更しないでください。
 _
Private Sub InitializeComponent()
components = New System.ComponentModel.Container
'★本来ならmainMenu1 = New System.Windows.Forms.Mainmenu(components)
mainMenu1 = New System.Windows.Forms.Mainmenu()
Me.Menu = mainMenu1
Me.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi
Me.Text = "Form1"
Me.AutoScroll = True
End Sub
End Class



しかし、それでもメモリは増え続けていきます・・・・


ダイアログフォームを起動し、ダイアログフォームを閉じる処理を1000回行い100回ごとにメモリ使用量を計測する処理を
以下の7種類のコードで試してみました。

コード1
Form2を起動し、Form2のActivatedでForm2を閉じます。
Form2にはmainMenuコントロールを1つ配置しています。
Using句を使用します。
Me.ListBox1.Items.Add("開始" & " : " & GC.GetTotalMemory(False))
For i As Int32 = 1 To 1000
Using frm As New Form2
frm.ShowDialog()
End Using
If i Mod 100 = 0 Then
Me.ListBox1.Items.Add(i.ToString & " : " & GC.GetTotalMemory(False))
End If
Next


コード2
Form2を起動し、Form2のActivatedでForm2を閉じます。
Form2にはmainMenuコントロールを1つ配置しています。
Using句を使用します。
GC.Collectを1回実行します。
Me.ListBox1.Items.Add("開始" & " : " & GC.GetTotalMemory(False))
For i As Int32 = 1 To 1000
Using frm As New Form2
frm.ShowDialog()
End Using
GC.Collect()
If i Mod 100 = 0 Then
Me.ListBox1.Items.Add(i.ToString & " : " & GC.GetTotalMemory(False))
End If
Next


コード3
Form3を起動し、Form3のActivatedでForm3を閉じます。
Form3にはmainMenuコントロールを1つ配置しています。
Form3のmainMenuコントロールはmainMenu1 = New System.Windows.Forms.Mainmenu(components)とします。
Using句を使用します。
GC.Collectを1回実行します。
Me.ListBox1.Items.Add("開始" & " : " & GC.GetTotalMemory(False))
For i As Int32 = 1 To 1000
Using frm As New Form3
frm.ShowDialog()
End Using
GC.Collect()
If i Mod 100 = 0 Then
Me.ListBox1.Items.Add(i.ToString & " : " & GC.GetTotalMemory(False))
End If
Next


コード4
Form2を起動し、Form2のActivatedでForm2を閉じます。
Form2にはmainMenuコントロールを1つ配置しています。
Try~finally句を使用します。
Me.ListBox1.Items.Add("開始" & " : " & GC.GetTotalMemory(False))
For i As Int32 = 1 To 1000
Dim frm As New Form2
Try
frm.ShowDialog()
Finally
frm.Dispose()
End Try
If i Mod 100 = 0 Then
Me.ListBox1.Items.Add(i.ToString & " : " & GC.GetTotalMemory(False))
End If
Next


コード5
Form2を起動し、Form2のActivatedでForm2を閉じます。
Form2にはmainMenuコントロールを1つ配置しています。
Try~finally句を使用します。
GC.Collectを1回実行します。
Me.ListBox1.Items.Add("開始" & " : " & GC.GetTotalMemory(False))
For i As Int32 = 1 To 1000
Dim frm As New Form2
Try
frm.ShowDialog()
Finally
frm.Dispose()
End Try
GC.Collect()
If i Mod 100 = 0 Then
Me.ListBox1.Items.Add(i.ToString & " : " & GC.GetTotalMemory(False))
End If
Next


コード6
Form2を起動し、Form2のActivatedでForm2を閉じます。
Form2にはmainMenuコントロールを1つ配置しています。
Try~finally句を使用します。
Form2にNothingを設定します。
GC.Collectを1回実行します。
Me.ListBox1.Items.Add("開始" & " : " & GC.GetTotalMemory(False))
For i As Int32 = 1 To 1000
Dim frm As New Form2
Try
frm.ShowDialog()
Finally
frm.Dispose()
frm = Nothing
End Try
GC.Collect()
If i Mod 100 = 0 Then
Me.ListBox1.Items.Add(i.ToString & " : " & GC.GetTotalMemory(False))
End If
Next


コード7
Form3を起動し、Form3のActivatedでForm3を閉じます。
Form3にはmainMenuコントロールを1つ配置しています。
Form3のmainMenuコントロールはmainMenu1 = New System.Windows.Forms.Mainmenu(components)とします。
Try~finally句を使用します。
GC.Collectを1回実行します。
Me.ListBox1.Items.Add("開始" & " : " & GC.GetTotalMemory(False))
For i As Int32 = 1 To 1000
Dim frm As New Form3
Try
frm.ShowDialog()
Finally
frm.Dispose()
End Try
GC.Collect()
If i Mod 100 = 0 Then
Me.ListBox1.Items.Add(i.ToString & " : " & GC.GetTotalMemory(False))
End If
Next




コード1、コード4はメモリ使用量はほぼ同じですが、他のコードと比べGC.Collectを実行していないので、最もメモリ使用量が高いです。
コード6以外のその他のコードはメモリ使用量はほぼ同じです。
圧倒的にメモリ使用量が少なく、メモリ増加量も少ないのがコード6でした。

う~ん・・・?ナゼ?

0 件のコメント: