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

DoEventsでメモリリーク?

環境/言語:[VB.NET/.NET Framework1.1]
分類:[.NET]

VB.NET 2003でWindowsアプリを作成しています。
長時間運用していると利用可能な物理メモリが減少していくようで(タスク
マネージャにて確認)、最終的にはアプリケーションの操作が不能となりま
す。
DevPartnerStudioというツールにてメモリリークを調査したところ、

Public Sub Wait(ByVal TT As Long)
' TTミリ秒間Waitする。
Dim T1 As Long, T2 As Long

T1 = System.Environment.TickCount
Do Until T2 - T1 >= TT
T2 = System.Environment.TickCount
System.Windows.Forms.Application.DoEvents()
Loop
End Sub

という関数のDoEventsにてメモリリークしているとの解析結果になりました。
本関数は他アプリとの通信の間、レスポンス待機中にユーザインタフェース
が使用不能にならないために準備している関数です。また、上記の関数は500
mS周期で継続的に呼び出しています。

ガベージコレクタは適宜起動されるため、上記のようなケースでメモリリーク
するようなことはないと考えていましたが、何か間違えがありますでしょうか。
どうか御教示願います。
2005/01/11(Tue) 16:09:03 編集(投稿者)

この関数ではなく、
Thread.Sleep メソッド ではだめですか?


>本関数は他アプリとの通信の間、レスポンス待機中に
>ユーザインタフェースが使用不能にならないために準備している

のであれば、スレッディングで対応できると思うのですが。

例:
Imports System
Imports System.Threading

Public Class ThreadExample
Public Shared Sub ThreadProc()
Dim i As Integer
For i = 0 To 9
Console.WriteLine("ThreadProc: 長くかかる処理を実行中です{0}/9", i)
' 時間をかけさせます。もしくは処理を行います。
Thread.Sleep(1000)
Next
End Sub

Public Shared Sub Main()
Console.WriteLine("Main thread: 新しいスレッドを準備→開始します。")
Dim t As New Thread(AddressOf ThreadProc)
t.Start()
Console.WriteLine("Main thread: 画面を待機中表示にします。")

Console.WriteLine("Main thread: Call Join()して,ThreadProc の終了を待ち受けます。.")
t.Join()
Console.WriteLine("Main thread: ThreadProc.Join から帰ってきました。 Press Enter to end program.")
Console.ReadLine()
End Sub
End Class
こんにちは、じゃんぬねっと です。

■No8329に返信(Mooさんの記事)
> この関数ではなく、
> Thread.Sleep メソッド ではだめですか?

では、描画はどうしましょうか? (w

■No8323に返信(そーですねぃさんの記事)
> 本関数は他アプリとの通信の間、
> レスポンス待機中にユーザインタフェースが
> 使用不能にならないために準備している関数です。
> また、上記の関数は500ms周期で継続的に呼び出しています。

とありますよ。

ちなみにこの現象、ソース抜粋部分が問題なのではなく
(Long (Int64) ではなく、Integer (Int32) だろという突っ込みはありますが)

> また、上記の関数は500ms周期で継続的に呼び出しています。

ここで、スレッドを使っているのが問題かなと思いました。
私の環境だとメモリリークなどしませんでしたから。



 /***************************************************
  * @Homepage    http://f57.aaa.livedoor.jp/~jeanne/
  * @Blog        http://www.ailight.jp/blog/jeanne/
  ***************************************************/
すみません、
私の書き込みがスレッドセーフじゃなかったようです。
こんにちは、じゃんぬねっと です。

■No8335に返信(Mooさんの記事)
> すみません、
> 私の書き込みがスレッドセーフじゃなかったようです。

Moo さん、ごめんなさい。

新たにインスタンスを生成 (修正) するとスレッドセーフではなくなりますから、
掲示板への書き込みは static (静的) にしないといけませんね (^-^A)



■No8323に返信(そーですねぃさんの記事)
蛇足になりますが、

> また、上記の関数は500ms周期で継続的に呼び出しています。

これは、500ms 周期で指定された秒間、"ずっと" Windows メッセージを受け付けてますよね。
そうではなくて、500ms 周期で 1 度だけ実行して、Windows メッセージを処理するべきでは?

後は、先の投稿で言った通り、メインスレッド側はどうなってるのかが問題かと。



 /***************************************************
  * @Homepage    http://f57.aaa.livedoor.jp/~jeanne/
  * @Blog        http://www.ailight.jp/blog/jeanne/
  ***************************************************/
Mooさん、じゃんぬねっとさん、早々に回答頂き有難う御座います。

>
>>また、上記の関数は500ms周期で継続的に呼び出しています。
>
> これは、500ms 周期で指定された秒間、"ずっと" Windows メッセージを受け付けてますよね。
> そうではなくて、500ms 周期で 1 度だけ実行して、Windows メッセージを処理するべきでは?
>
> 後は、先の投稿で言った通り、メインスレッド側はどうなってるのかが問題かと。
>
上記内容がスムーズに理解できていません。(;;)
実は500ms周期でスレッドを作成しながら、そのスレッド内でWait(500)なんて処理を
行っていました。正確ではないですが、以下のようなコードです。

 SyncLock
If a==b Then
Wait(500)
End If
End SyncLick

つまり500mS待っている間に次のスレッドが作成されてしまっているような状況です。
上記の御指摘はこのような処理を行ってはいけない。(1つのスレッドのみが実行さ
れている状況を確実にしなさい)ということを仰られているのでしょうか。

ただ、このようなコードでも少々実行を待たされるスレッドはあるものの、起動されて
いるスレッドはせいぜい2〜3個であり、リソースを食いつぶすようなことはないので
はないかと考えています。

どうでしょうか?
■No8323に返信(そーですねぃさんの記事)

こんにちは 平ちゃんです。

>上記の関数は500mS周期で継続的に呼び出しています。
このような間隔の長い場合はTimerクラスで十分対応できると思いますが。

> ガベージコレクタは適宜起動されるため・・・
自前でガベージコレクタを操作するのは難しいと
色々な本に書かれていました。
こんにちは、じゃんぬねっと です。

■No8338に返信(そーですねぃさんの記事)
> 正確ではないですが、以下のようなコードです。

小出しにされても、解決には結びつかないのでは?
どの部分の抜粋なのか、その前後関係がわかりにくいのではないでしょうか?
それに、"正確"じゃないってどれくらいのことなんでしょ?
あなたのコードはあなたにしかわかりませんよね。

> つまり500mS待っている間に次のスレッドが作成されてしまっているような状況です。
> 上記の御指摘はこのような処理を行ってはいけない。(1つのスレッドのみが実行さ
> れている状況を確実にしなさい)ということを仰られているのでしょうか。

えーと、1つのスレッドというとメインスレッドだけになってしまいますから、
それだと画面の描画ができなくなっちゃうのではないでしょうか?

> ただ、このようなコードでも少々実行を待たされるスレッドはあるものの、起動されて
> いるスレッドはせいぜい2〜3個であり、リソースを食いつぶすようなことはないので
> はないかと考えています。

え? 2つじゃないのですか? 2〜3個? (^-^;)

# まずは、スレッドを外した状態でテストしてみて、メモリリークを起こすかチェックするとか...。
# 単にコードを眺めて原因を探っても、時間が勿体無いでしょうから。
# 原因となりそうな、部分をコメントアウトなどしてみてください。



   /*******************************************
     * @Homepage  http://f57.aaa.livedoor.jp/~jeanne/
     * @Blog        http://www.ailight.jp/blog/jeanne/
     *******************************************/
  • 題名: Re[7]: DoEventsでメモリリーク?
  • 著者: そーですねぃ
  • 日時: 2005/01/11 18:55:15
  • ID: 8343
  • この記事の返信元:
  • この記事への返信:
    • (なし)
  • ツリーを表示
平ちゃんさん、有難うございます。

> >上記の関数は500mS周期で継続的に呼び出しています。
> このような間隔の長い場合はTimerクラスで十分対応できると思いますが。
>
そうですね。色々無駄なことをやっているようです。
タイマイベント毎にスレッドを作成していたのですが、
それは不要であると気づいて試行している最中です。

>>ガベージコレクタは適宜起動されるため・・・
> 自前でガベージコレクタを操作するのは難しいと
> 色々な本に書かれていました。
>
私もそのように読みました。ガベージコレクタはス
レッドが終了すればOSが勝手に呼び出してくれるも
のと考えています。従って自前では操作していませ
ん。


じゃんぬねっとさん、お世話になります。

>>正確ではないですが、以下のようなコードです。
>
> 小出しにされても、解決には結びつかないのでは?
> どの部分の抜粋なのか、その前後関係がわかりにくいのではないでしょうか?
> それに、"正確"じゃないってどれくらいのことなんでしょ?
> あなたのコードはあなたにしかわかりませんよね。
>
申し訳ないです。切り出し方が悪くてわかりにくいものと
なってますよね。500mS毎の起動の中に500mSのWaitが入っ
ていることを説明したかっただけです。

>>つまり500mS待っている間に次のスレッドが作成されてしまっているような状況です。
>>上記の御指摘はこのような処理を行ってはいけない。(1つのスレッドのみが実行さ
>>れている状況を確実にしなさい)ということを仰られているのでしょうか。
>
> えーと、1つのスレッドというとメインスレッドだけになってしまいますから、
> それだと画面の描画ができなくなっちゃうのではないでしょうか?
>
表現がおかしかったですね。
メインスレッドの他に1スレッドという意味です。

>>ただ、このようなコードでも少々実行を待たされるスレッドはあるものの、起動されて
>>いるスレッドはせいぜい2〜3個であり、リソースを食いつぶすようなことはないので
>>はないかと考えています。
>
> え? 2つじゃないのですか? 2〜3個? (^-^;)
>
これも表現がおかしかったですね。上記のコードでは2つです。
(もちろんメインスレッドの他に。。。です。)
どうもすいません。

> # まずは、スレッドを外した状態でテストしてみて、メモリリークを起こすかチェックするとか...。
> # 単にコードを眺めて原因を探っても、時間が勿体無いでしょうから。
> # 原因となりそうな、部分をコメントアウトなどしてみてください。
>
そうですね。現在スレッドを使わずに試行中です。
また、結果を報告させて頂きます。

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