質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.49%
VB.NET

Microsoft Visual Basic .NETのことで、Microsoft Visual Basic(VB6)の後継。 .NET環境向けのプログラムを開発することができます。 現在のVB.NETでは、.NET Frameworkを利用して開発を行うことが可能です。

Q&A

解決済

1回答

6271閲覧

【VB.NET】Labelコントロールのテキスト変更によるメモリリークについて

garakutayama

総合スコア7

VB.NET

Microsoft Visual Basic .NETのことで、Microsoft Visual Basic(VB6)の後継。 .NET環境向けのプログラムを開発することができます。 現在のVB.NETでは、.NET Frameworkを利用して開発を行うことが可能です。

0グッド

1クリップ

投稿2018/05/15 07:44

編集2018/05/16 02:43

前提・実現したいこと

VB.NETにてUIソフトを作製しておりますが、メモリリークが発生してソフトが終了してしまいました。
その解決に向けて調査している中で、私には理解できない現象が発生したので教えて頂ければ幸いです。

現象

メモリリークの原因を調べる中で、Labelコントロールに時刻表示(毎秒更新)する機能の有り無しでタスクマネージャの
メモリ使用量が大きく変わることが分かりました。(モジュール①は毎秒更新、モジュール②は更新なしです)

しかし両モジュール共にGC.Collect()した後に、GC.GetTotalMemory(True)で使用量を確認すると、増加しませんでした。

各モジュールを比べると以下のような状態です。

モジュールタスクスケジューラGC.GetTotalMemory(True)
①(始め)30.7 MB5365.9296875 KB
①(1H後)114.6 MB5367.890625 KB
②(始め)24.5 MB5379.09375 KB
②(1H後)24.7 MB5383.109375 KB

モジュール①: 時刻ラベルを毎秒更新

VB.NET

1 Public Sub EverySecProcess() 2 lbl_DateTime.Text = Date.Now.ToString("MM/dd HH:mm:ss") '日時ラベルの表示 3 GC.Collect() 4 GC.WaitForPendingFinalizers() 5 GC.Collect() 6 SaveMemoryLog(MethodBase.GetCurrentMethod.Name & ".SetText---End") 'メモリ量ロギング 7 End Sub

モジュール②: 時刻ラベルを更新しない

VB.NET

1 Public Sub EverySecProcess() 2 'lbl_DateTime.Text = Date.Now.ToString("MM/dd HH:mm:ss") '日時ラベルの表示 3 GC.Collect() 4 GC.WaitForPendingFinalizers() 5 GC.Collect() 6 SaveMemoryLog(MethodBase.GetCurrentMethod.Name & ".SetText---End") 'メモリ量ロギング 7 End Sub

(参考メモリ量ロギング)

VB.NET

1 Public Sub SaveMemoryLog(ByVal MethodName As String) 2 Dim fs As System.IO.FileStream = Nothing 3 4 Try 5 fs = New System.IO.FileStream(MyPath.MemoryLog, IO.FileMode.Append, IO.FileAccess.Write, IO.FileShare.ReadWrite) 6 7 Using sw As New System.IO.StreamWriter(fs, enc) 8 Using tw As System.IO.TextWriter = System.IO.TextWriter.Synchronized(sw) 9 Dim MsgBuf As String = Date.Now.ToString("yyyy/MM/dd HH:mm:ss:fff") & vbTab 10 MsgBuf &= "Total Memory = " & (GC.GetTotalMemory(True) / 1024).ToString.PadRight(12, " ") & " KB" & vbTab 11 MsgBuf &= MethodName 12 13 tw.WriteLine(MsgBuf) 14 tw.Close() 15 End Using 16 sw.Close() 17 End Using 18 Catch ex As Exception 19 'ここでは何もしない 20 Finally 21 'fsがusingでは無く、finallyでcloseしているのは、swのDispose時にすでにcloseされている可能性が有るため 22 If fs IsNot Nothing Then 23 fs.Close() 24 fs.Dispose() 25 fs = Nothing 26 End If 27 End Try 28 End Sub

質問内容

  • ①変更点は時刻の毎秒更新のみ(changeイベントなども組んでいない)なのですが、これがメモリリークの原因になりうるのでしょうか

  • ②もし①が起こりうるのであれば、メモリリークでソフトが落ちないようにするにはどうすれば良いのでしょうか。

補足情報(FW/ツールのバージョンなど)

  • 動作環境
    OS: Windows 10 IoT 2016LTSB (UWF ON)

  • 開発環境
    開発ツール: Visual Studio 2012
    言語: VB.NET
    対象のフレームワーク: .Net Flamework 4.5

追記① EverySecProcessの呼出元について

スタートアップフォームに作成したtmr_OneSecのTickイベントにて呼んでいます。

VB.NET

1 2 Private Sub tmr_OneSec_Tick(sender As Object, e As EventArgs) Handles tmr_OneSec.Tick 3 If MyStatus.IsInitialization Then '初期設定中はタイマー処理は実施しない 4 Exit Sub 5 End If 6 7 EverySecProcess() '毎秒処理の実行 8 9 If OneMinuteCount >= 59 Then '毎分処理の実行 10 OneMinuteCount = 0 11 EveryMinProcess() 12 Else 13 OneMinuteCount += 1 14 End If 15 End Sub 16

追記② ウィンドウメッセージの処理

大変申し訳ありません。
改めて見直したところ対象フォームのウィンドウメッセージをオーバーライドしていることが分かりました。
(デバイスの利用の為に作成したが消し忘れていたようです)

この関数をコメントアウトしたところ少し見た限りではモジュール①の状態でもリークしないようになりました。
しばらく様子を見たいと思います。

画面更新等の処理はないとの間違った情報を提示してしまい申し訳ありませんでした。

また新たな疑問として下記の処理でリークする理由(なぜLabelのtextchangeでリークするのか)についても、詳しく調べていきたいと思います。

VB.NET

1 Protected Overrides Sub WndProc(ByRef m As Message) 2 SPREAD.SuspendLayout()'別のスプレッドシートの描画停止処理 3 Try 4 Select Case m.Msg 5 ''Case WINDOW_MESSAGE._DIOEVENT 6 ''SignalInput(Integer.Parse(m.WParam.ToString)) '監視対象の機器&立ち上がり信号の場合、信号受信処理実行 7 Case Else 8 MyBase.WndProc(m) '<フォームの標準処理の実行> 9 End Select 10 Catch ex As Exception 11 SaveErrorLog(MethodBase.GetCurrentMethod.Name, ex, "m:" & m.Msg) 12 End Try 13 SPREAD.ResumeLayout() 14 End Sub

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

sh_akira

2018/05/15 07:54

そもそもEverySecProcessはどうやって呼んでいますか?きちんとUIスレッドでしょうか?
garakutayama

2018/05/15 08:08

早速のご返信ありがとうございます。ラベルの存在するフォームのデザイン上に作成したタイマーのTickイベントにて呼んでおります。質問文にソースを追記しましたのでご確認ください。
sh_akira

2018/05/15 08:41

特に問題なさそうですね。GetTotalMemoryとタスクマネージャは見ている値が違う可能性があります。ワーキングセットとプライベートワーキングセットの違い等です。ヒープサイズが増えているだけで特に問題ないように思います。タスクマネージャで表示する列を増やしてみることをお勧めします。
garakutayama

2018/05/15 09:25

メモリについて内容を完全に理解できていませんが、助言頂いた内容でモジュール①②をくらべました。結果、共有ワーキングセットは同じくらいの使用量でプライベートワーキングセットは①291,800K、②25,688Kと大きく異なっていることがわかりました。その結果の良不良が判断出来ないのですが、プライベートワーキングセットが増えることは問題(System.OutOfMemoryExceptionが発生する)のように感じましたが間違っておりますでしょうか。
YAmaGNZ

2018/05/15 14:10

ラベルのテキストの更新をすることで動作する処理(フォームの再描画等)はありますか?
garakutayama

2018/05/16 00:53

返信ありがとうございます。テキスト更新にて動作するイベントとしてはLabelコントロールのTextChangedイベントおよび、その他のtext変更イベントでの描画更新は有りません。
garakutayama

2018/05/16 02:45

@sh_akira様、@YAmaGNZ様 大変申し訳ありませんでした。改めて確認したところウィンドウメッセージをオーバーライドしており、その処理をコメントアウトするとモージュール①でもリークしないことが分かりました。描画更新処理はないと書いてしまいましたが訂正するとともに、お詫び申し上げます
guest

回答1

0

自己解決

皆様ご確認ありがとうございました。

結論としてウィンドウメッセージをオーバーライドしており、その処理をコメントアウトするとモージュール①でもリークしないことが分かりました。

確認不足でお騒がせし申し訳ありませんでした。

なぜリークするのかはまだ調査中ですが、いったん本質問はクローズとさせていただきたいと思います。

投稿2018/05/17 07:48

garakutayama

総合スコア7

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.49%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問