C# と VB.NET の質問掲示板

ASP.NET、C++/CLI、Java 何でもどうぞ

C# と VB.NET の入門サイト

Re[17]: ガベージコレクションについて


(過去ログ 51 を表示中)

[トピック内 37 記事 (1 - 20 表示)]  << 0 | 1 >>

■28198 / inTopicNo.1)  ガベージコレクションについて
  
□投稿者/ nori (29回)-(2008/11/21(Fri) 00:27:02)

分類:[.NET 全般] 

public Form()
{
   InitializeComponent();

   System.Timers.Timer timer = new System.Timers.Timer(100000);
   timer.Elapsed += new System.Timers.ElapsedEventHandler(timer_Elapsed);
   timer.AutoReset = false;
   timer.Start();
}

void timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
   何らかの処理
}

FormのコンストラクタでSystem.Timers.Timerを作ります。(Formのメンバー変数として持ちません)
この場合、Formが生きてる限りガベージコレクションによりTimerオブジェクトが回収される事は無いのでしょうか?
(生きてるFormのtimer_Elapsedと紐付いているので)

また、上記で回収されないとした場合、timerオブジェクトが回収対象となるタイミングは
Formが誰からも参照されなくなった時でしょうか?

引用返信 編集キー/
■28203 / inTopicNo.2)  Re[1]: ガベージコレクションについて
□投稿者/ 渋木宏明(ひどり) (952回)-(2008/11/21(Fri) 01:54:25)
渋木宏明(ひどり) さんの Web サイト
> FormのコンストラクタでSystem.Timers.Timerを作ります。(Formのメンバー変数として持ちません)
> この場合、Formが生きてる限りガベージコレクションによりTimerオブジェクトが回収される事は無いのでしょうか?
> (生きてるFormのtimer_Elapsedと紐付いているので)

逆でしょ?

参照されているのは Form.timer_Elapsed() の方です。

Timer は誰からも参照されていないので、いずれガベージコレクタによって回収されてしまいます。

引用返信 編集キー/
■28206 / inTopicNo.3)  Re[1]: ガベージコレクションについて
□投稿者/ まんごーぷりん (40回)-(2008/11/21(Fri) 09:33:05)
まんごーぷりん さんの Web サイト
2008/11/21(Fri) 09:33:55 編集(投稿者)

No28198 (nori さん) に返信
>
> FormのコンストラクタでSystem.Timers.Timerを作ります。(Formのメンバー変数として持ちません)
> この場合、Formが生きてる限りガベージコレクションによりTimerオブジェクトが回収される事は無いのでしょうか?
> (生きてるFormのtimer_Elapsedと紐付いているので)

イベントに対してメソッドを登録したことが生きているという意味ではないです。

通常、インスタンスを生成したものが、どこで解放されるのかを考えてみましょう。
コンストラクタといえども、単なるメソッドのブロックですよね?

引用返信 編集キー/
■28250 / inTopicNo.4)  Re[2]: ガベージコレクションについて
□投稿者/ nori (30回)-(2008/11/21(Fri) 22:46:00)
レスありがとうございます。

回収さちゃうんですね。
と言う事は、上記の処理はかなり分かり難いバグですね。

# 世の中上のようなコードってかなりありそうな気がする
# 2回目のガベージじゃないとタイマー止まらないから大丈夫?なのかな。。。

ありがとうございました
引用返信 編集キー/
■28251 / inTopicNo.5)  Re[3]: ガベージコレクションについて
□投稿者/ nori (31回)-(2008/11/21(Fri) 22:46:26)
解決!
解決済み
引用返信 編集キー/
■28268 / inTopicNo.6)  Re[3]: ガベージコレクションについて
□投稿者/ .SHO (143回)-(2008/11/22(Sat) 13:31:00)
2008/11/22(Sat) 13:31:44 編集(投稿者)

No28250 (nori さん) に返信

> と言う事は、上記の処理はかなり分かり難いバグですね。
>
> # 世の中上のようなコードってかなりありそうな気がする
> # 2回目のガベージじゃないとタイマー止まらないから大丈夫?なのかな。。。

上記のソースにバグはありません。
回収されるのは timer で timer_Elapsed ではないからです。

この実験をするなら timer.AutoReset は false ではなく true にすべきでしょう。
もし timer が 1回で止まってしまうのが、回収されてしまったせいだと思っているなら
それは勘違いです。


timer.AutoReset を true にして、もう一度試してみてください。
解決済み
引用返信 編集キー/
■28276 / inTopicNo.7)  Re[4]: ガベージコレクションについて
□投稿者/ なちゃ (209回)-(2008/11/22(Sat) 15:39:08)
いやまず普通はバグでしょう。
うっかりやってしまうと気もつきにくいですね。

解決済み
引用返信 編集キー/
■28277 / inTopicNo.8)  Re[5]: ガベージコレクションについて
□投稿者/ .SHO (148回)-(2008/11/22(Sat) 15:44:16)
2008/11/22(Sat) 15:44:27 編集(投稿者)

No28276 (なちゃ さん) に返信

> いやまず普通はバグでしょう。

timer.AutoReset を false にしたことがバグだという意味ですか?
解決済み
引用返信 編集キー/
■28279 / inTopicNo.9)  Re[6]: ガベージコレクションについて
□投稿者/ オショウ (59回)-(2008/11/22(Sat) 17:23:10)
横からすいません・・・

public Form() のAuto変数に、timer が宣言されているので
関数抜ければ当然回収されるのは、あたりまえです。

と言う意味で、バグだと言えば、宣言の仕方がまずいと言う
ことと思いますが。

以上。

引用返信 編集キー/
■28280 / inTopicNo.10)  Re[7]: ガベージコレクションについて
□投稿者/ .SHO (150回)-(2008/11/22(Sat) 17:42:09)
No28279 (オショウ さん) に返信

> public Form() のAuto変数に、timer が宣言されているので
> 関数抜ければ当然回収されるのは、あたりまえです。
>
> と言う意味で、バグだと言えば、宣言の仕方がまずいと言う
> ことと思いますが。

そうなんですか???

そうだとすると、もし AutoReset が true だった場合、回収された後はどうなるのですか?
timer_Elapsed で例外が発生する?

そもそも、本当に回収されるのかな?
引用返信 編集キー/
■28281 / inTopicNo.11)  Re[8]: ガベージコレクションについて
□投稿者/ .SHO (151回)-(2008/11/22(Sat) 18:31:18)
上記ソースを確認のためにタイマーを 100000 ではなく 1000 にし
AutoReset を true にして、1時間近く動かし続けましたが
何の問題もなく動き続けてます。

ガーベジコレクタの動きを細かく検証したことはないですが
たぶん timer.Start(); をかけた時点で、タイマー使用中みたいな
フラグが立って回収されないんじゃないでしょうか?

そうじゃないと、C#って相当注意深くガーベジコレクタの動きを
考慮していないと、まともなプログラムなんて作れないです。

そもそも、ガーベジコレクタの動きなんて意識せずにコーディング
できなければ意味がないです。
引用返信 編集キー/
■28283 / inTopicNo.12)  Re[9]: ガベージコレクションについて
□投稿者/ オショウ (60回)-(2008/11/22(Sat) 20:19:44)
2008/11/22(Sat) 20:23:10 編集(投稿者)

> 上記ソースを確認のためにタイマーを 100000 ではなく 1000 にし
> AutoReset を true にして、1時間近く動かし続けましたが
> 何の問題もなく動き続けてます。

  ガーベージの動作ですが・・・
  別件で・・・
  未検証ですが、1秒なら回収されませんでした。
  90秒〜120秒アクセスしなければ回収される
  頻度が高くなった記憶があります。

  因みに、VB6時代のActiveXをフォームに貼って一度
  動作させた後、長時間(2分以上)アクセスしない
  とフォームに貼ってあるActiveXすら回収されてし
  まいエラーとなったことがあります。

  原因を追究する時間が当時無かったので、タイマー
  中にダミーの空アクセスを行なうようにして回収さ
  れないように回避させたことがありました。

● 今回のケースで・・・
  100秒間隔のタイマーと言う設定は仕様的に可能でも
  問題が出ることが多分にあるので、1〜10秒とし
  てイベント内で回数をカウントし、所定回数イベン
  トが発生したら本来の処理を行なう。と言う風にす
  るのが最善かと。

  1秒間隔なら100回カウント
  10秒間隔なら10回カウント

  異論はあると思いますが、私はそうやって長時間の
  タイマー間隔の動作を保全しています。

  あと変数の宣言ですが、Auto変数はどうかと・・・
  クラス内でPrivate とかで宣言した方がよいと思い
  ますが。

  スレッドや別インスタンス空間からのアクセスがあ
  るならPivate Shared ですか・・・(VBの場合)

  AutoResetに影響があるかについては未確認です。
  あしからず。

以上。
引用返信 編集キー/
■28284 / inTopicNo.13)  Re[9]: ガベージコレクションについて
□投稿者/ 渋木宏明(ひどり) (957回)-(2008/11/22(Sat) 20:42:32)
渋木宏明(ひどり) さんの Web サイト
> 上記ソースを確認のためにタイマーを 100000 ではなく 1000 にし
> AutoReset を true にして、1時間近く動かし続けましたが
> 何の問題もなく動き続けてます。

であっても、何かを証明したことにはならないでよね。

> そもそも、ガーベジコレクタの動きなんて意識せずにコーディング
> できなければ意味がないです。

それは大きな誤解です。

ガベージコレクタが管理しているのは、あくまで「マネージヒープ上に確保されたメモリ」だけです。

ウィンドウやファイル、タイマ等々、OSが管理しているリソースを使用する際は、それらの寿命管理はプログラマの責任で行うものなのです。

引用返信 編集キー/
■28285 / inTopicNo.14)  Re[10]: ガベージコレクションについて
□投稿者/ NyaRuRu (72回)-(2008/11/22(Sat) 21:07:26)
2008/11/22(Sat) 21:08:33 編集(投稿者)
2008/11/22(Sat) 21:07:57 編集(投稿者)

No28284 (渋木宏明(ひどり) さん) に返信
> ウィンドウやファイル、タイマ等々、OSが管理しているリソースを使用する際は、それらの寿命管理はプログラマの責任で行うものなのです。

実際,公開されている BCL のソースを呼んでみると,ライブラリ側で GC 回避の工夫が行われているケースもありますね.
以前 System.Windows.Forms.Timer (今回問題になっている System.Timers.Timer ではない) のソースを確かめてみたら,タイマを有効にしている間は GCHandle で自分自身をルート参照に加えていました.

他方,System.Threading.Timer (これも今回問題になっている System.Timers.Timer ではない) はそういう処理を呼び出し側の責任ととらえているのか,ドキュメントにはこう書かれたままですね.
http://msdn.microsoft.com/ja-jp/library/system.threading.timer.aspx
>Timer を使用している間は、このクラスへの参照を保持しておく必要があります。
>他のマネージ オブジェクトと同様、まったく参照されていない場合、Timer はガベージ コレクションの対象となります。
>Timer がアクティブであっても、ガベージ コレクションの対象から除外されることはありません。
(こちらもソースが公開されてますので,興味がある方は実際の実装がどうなっているか調べてみてください)

引用返信 編集キー/
■28287 / inTopicNo.15)  Re[11]: ガベージコレクションについて
□投稿者/ なちゃ (210回)-(2008/11/22(Sat) 23:58:59)
すみません、System.Threading.Timer に書かれている(NyaRuRu さんが引用されている)記述と、System.Timers.Timer を混同してました。

System.Timers.Timerの方は何も言及されていないですね。
System.Threading.Timerにあえて注意が書かれていることを考えれば、System.Timers.Timerの方は問題ないというように期待することもできますね。
手元である程度それっぽく試してみた限りでは問題なさそうに見えます(試した限りでは、ですが)。

そういえば、参照が回りまわってどうやら大丈夫っぽいかなってことを、以前@ITだったかどっかで自分で書いたことがあったような気がしてきました。

System.Timers.TimerはSystem.Threading.Timerを使用していると某書籍に書いてあったので、私はついなんとなく駄目っぽく感じてしまうんですが、
System.Threading.Timer自体はGCの対象になっても、登録したコールバックのデリゲートは残る形になっていて、それがおそらくSystem.Timers.Timerインスタンスの内部ハンドラという形になっていると思われるので、
結果としてSystem.Timers.TimerはGCの対象にならないって感じに予想されます。


というわけで、System.Timers.Timerに関しては単純に私の勘違いです。
ただ、System.Threading.Timerのような例もありますので、
>そうじゃないと、C#って相当注意深くガーベジコレクタの動きを
>考慮していないと、まともなプログラムなんて作れないです。
ものによってはやっぱり注意が必要なことはあります。

引用返信 編集キー/
■28289 / inTopicNo.16)  Re[11]: ガベージコレクションについて
□投稿者/ nori (32回)-(2008/11/23(Sun) 00:32:27)
2008/11/23(Sun) 00:33:04 編集(投稿者)

気づかない間にスレが伸びてる。

一応私の理解。
timerはform(timer_Elapsed)を参照している
だけど、formはtimerを参照していない
GCはルートから参照しているインスタンスを検索するので、formから参照されていないtimerはGCの対象になる。
という事で理解しました。

>.SHOさんの発言
>上記のソースにバグはありません。
>回収されるのは timer で timer_Elapsed ではないからです。
私がバグと言ったのは、timerが回収されるという事はfinalyzeでtimerが止められる(なのでGC2回)、
よって場合によってはtimer_ElapsedがCALLされないのでバグと言いました。

>.SHOさんの発言
>この実験をするなら timer.AutoReset は false ではなく true にすべきでしょう。
>もし timer が 1回で止まってしまうのが、回収されてしまったせいだと思っているなら
>それは勘違いです。
>timer.AutoReset を true にして、もう一度試してみてください。
trueにした場合、timerを止める為に誰かが参照を持たないといけません。
ですので、質問用サンプルを作るのが楽なfalseを使いました。

>NyaRuRuさんの発言
>実際,公開されている BCL のソースを呼んでみると,ライブラリ側で GC 回避の工夫が行われているケースもありますね.
>以前 System.Windows.Forms.Timer (今回問題になっている System.Timers.Timer ではない) のソースを確かめてみたら,
>タイマを有効にしている間は GCHandle で自分自身をルート参照に加えていました.
なんと!こんな便利なものがあったんですね。
GC.KeepAliveじゃ回避できなし、必ず参照を持つしか無いのかと思っなちゃてました。
これであれば、使用者の負担が無くなるからいいですね。
なぜSystem.Threading.Timerは、使用してないのが疑問ですが・・・

>なちゃさんの発言
>System.Timers.TimerはSystem.Threading.Timerを使用していると某書籍に書いてあったので、私はついなんとなく駄目っぽく感じてしまうんですが、
>System.Threading.Timer自体はGCの対象になっても、登録したコールバックのデリゲートは残る形になっていて、
>それがおそらくSystem.Timers.Timerインスタンスの内部ハンドラという形になっていると思われるので、
>結果としてSystem.Timers.TimerはGCの対象にならないって感じに予想されます。
すみません、意味が良くわからないので、もう少し詳しく教えていただけると助かります。

良い情報が聞けました。
皆様ありがとうございます
引用返信 編集キー/
■28354 / inTopicNo.17)  Re[10]: ガベージコレクションについて
□投稿者/ .SHO (154回)-(2008/11/25(Tue) 10:10:02)
No28284 (渋木宏明(ひどり) さん) に返信

>>上記ソースを確認のためにタイマーを 100000 ではなく 1000 にし
>>AutoReset を true にして、1時間近く動かし続けましたが
>>何の問題もなく動き続けてます。
>
> であっても、何かを証明したことにはならないでよね。

完全な証明でないことはわかってますが、1時間も動かせば必要十分な証明だと思います。
100秒、200秒の世界の話をしているわけですから。

もし、GCによって回収されたこと(回収されないこと)を確実に判断する方法があるなら
是非、ご教授願います。

引用返信 編集キー/
■28357 / inTopicNo.18)  Re[10]: ガベージコレクションについて
□投稿者/ .SHO (155回)-(2008/11/25(Tue) 11:21:02)
No28283 (オショウ さん) に返信

>   未検証ですが、1秒なら回収されませんでした。
>   90秒〜120秒アクセスしなければ回収される
>   頻度が高くなった記憶があります。

もしそうなら、随分といい加減というかアバウトな実装がされてることになりますね。
実際はそんなことはないと思います。

未検証ということなので、最初のプログラムのタイマを120秒にし「何らかの処理」の
部分を「Console.WriteLine( DateTime.Now );」にしたプログラムを動かしてますが
何も問題なく動きます。

とりあえず1時間ほど動かしましたが、またそれじゃ何の証明にもならないと
突っ込まれそうなので、今日帰宅時にPCを落とすか、PCが他の作業で死ぬまで
このまま動かし続けてみます。
(それでも完全な証明にはならないことはわかってますが…)
引用返信 編集キー/
■28359 / inTopicNo.19)  Re[11]: ガベージコレクションについて
□投稿者/ なちゃ (211回)-(2008/11/25(Tue) 11:49:53)
時間よりも、少なくとも GC が何度か動作した後で見ることが重要かと思います。

世代とファイナライザのことを考えると、明示的にGCを起こしたりファイナライザの完了を待った方がいいかな。
デバッグ実行だとメソッド抜けてからでないとダメかも。
この辺は色々ありますが。

まあいずれにしても保証はありませんが、GCによる回収が働くかに関しては、まずまず確認出来ると思います。

引用返信 編集キー/
■28360 / inTopicNo.20)  Re[10]: ガベージコレクションについて
 
□投稿者/ .SHO (156回)-(2008/11/25(Tue) 11:53:00)
No28283 (オショウ さん) に返信

>   あと変数の宣言ですが、Auto変数はどうかと・・・
>   クラス内でPrivate とかで宣言した方がよいと思い
>   ますが。

Auto変数にしない方が間違いはないというのはわかりますが
Auto変数でいいのかどうかが、この質問の本質だと思うので
Auto変数で問題ないと思います。

たとえば、Formのコンストラクタの中で
MainMenu menu = new MainMenu();
this.Menu = menu;
として作成したメニューは、いずれGCによって回収され
壊れてしまうのでしょうか?
実際はそんなことはなく、問題なく動きます。
引用返信 編集キー/

次の20件>
トピック内ページ移動 / << 0 | 1 >>

管理者用

- Child Tree -