トップ回答者
プログレスバーのグラヒカルインジケータが真っ黒になりエラーが表示される

質問
-
お世話になっております。
Visual Studio 2005 C#でWindows Formアプリケーションを作っています。
そのアプリケーションの動作でおかしな現象が出て解決できずに困っております。
直接C#には関係しないのかもしれませんが、解決策、回避策、ここを尋ねればなど
ありましたらご教示をお願いいたします。[現象]
プログレスバー表示をスタートから終了までで一回(プログレスバーが閉じる)として、これを12時間~24時間
連続で実行させると、プログレスバーのグラヒカルインジケータが真っ黒になりエラーが表示される。
また、エラーは"Attempted to divide by zero"と表示される。[質問事項]
・OS(又は.NetFramework)の仕様なのでしょうか?
・アプリケーション(プログラム)での対応策などはあるのでしょうか?
・対策があった場合、その対策が他のOS(Vistaや2000SP4)などに影響を与えることはないのでしょうか?[現象確認OS]
WindowsXP Professional SP2
WindowsXP Professional SP3[アプリケーション開発環境]
VisualStadio 2005 C# Ver8.0.5
.NetFramework ver2.0
回答
-
こんにちは!(^^)!ふ~です。
プログレスバーだけの試験は、簡単に100000回を超えてしまいました。これにフォームの表示、非表示を加え、平均的に動作するように、ガベージコレクション処理を加えると、問題無く動作しております。
<連続動作可能なソース>
namespace WinProgressCountTest
{
public partial class Form1 : Form
{
private int iValue = 0;
private bool bEnd = false;
private Progress clsProgress = null;
private long lCount = 0L; // タイマーカウンターpublic Form1()
{
InitializeComponent();// タイマーのインターバル時間
this.tmProgressCount.Interval = 5;
}private void button1_Click(object sender, EventArgs e)
{// タイマースタート
this.tmProgressCount.Start();// プログレスバーの初期化
this.clsProgress = new Progress();
this.clsProgress.iProgress = 0;
this.iValue = 0;
this.bEnd = false;// プログレスバー(Form2)を表示
this.clsProgress.ShowDialog(this);}
private void timer1_Tick(object sender, EventArgs e)
{
// Form2のインスタンスが無い場合
if (clsProgress == null) return;// 処理時間を測定する
DateTime startTime = DateTime.Now;
// タイマー終了フラグを確認する。
if (!this.bEnd) {
// 進捗が100になったかを確認。
if (iValue == 100) {
// タイマー終了フラグを変更
this.bEnd = true;// Form2を隠す
this.clsProgress.Hide();// ガベージコレクションを行う。
GC.Collect();} else {
// 進捗が100になっていなければ10インクリメントして
// プログレスバーに設定する。
iValue += 10;
this.clsProgress.iProgress = iValue;
}
} else {
// プログレスバーをクリアする。
this.iValue = 0;
this.clsProgress.iProgress = iValue;
this.bEnd = false;// Form2を表示する
this.clsProgress.Show();
}lCount++;
Debug.WriteLine("タイマー処理 発生回数=" + lCount.ToString());
TimeSpan diff = DateTime.Now - startTime;
Debug.WriteLine("処理時間=" + (diff.Ticks / 10000) + " ms");
// 使用メモリを表示する
Debug.WriteLine(System.GC.GetTotalMemory(false).ToString()+" byte");// 終了判断条件
if (100000L < lCount)
{
// タイマースタート
this.tmProgressCount.Stop();// Form2クローズする
this.clsProgress.Close();Debug.WriteLine("お疲れ様です。無事、耐久試験完了致しました。");
}
}
}
}◇[まとめ]
繰り返しに向かない組み合わせ
1)this.clsProgress.ShowDialog(this) と this.clsProgress.Hide()
2)new() と this.clsProgress.ShowDialog(this) と this.clsProgress.Close()
連続繰り返しに耐える組み合わせ
1)this.clsProgress.Show() と this.clsProgress.Hide() (息継ぎが有る)
2)this.clsProgress.Show() と this.clsProgress.Hide() と GC.Collect() (平均安定動作)
フォーム2の表示速度も.Show()とHide() が圧倒的に速いです。C#でも、用途にあわせて、メソッドを選ばないと性能がでないようです。ご参考になれば幸いです。
すべての返信
-
!(^^)!ふ~ さんからの引用 連続使用で、メモリ管理の問題と思います。検討には、再現できる簡単なサンプルが必要です。
!(^^)!ふ~さん。じゃんぬねっとさん。返信ありがとうございました。再現できる簡単なサンプルを作りました。
なにかおかしなところがあれば、ご指摘おねがいします。
[動作]
メインフォーム上のボタンが押されたら、別のフォームで
100000回プログレスバーを表示するものです。[クローズ処理]
クローズは、タイマー処理部分で"this.clsProgress.Close();"を行っています。[フロー]
Form1:スタートをするためのフォーム
Form2:プログレスバーを表示するフォーム1.Form1のボタン押下でタイマーをスタート
↓
2.プログレスバーの状態や進捗率を初期化し、Form2を表示。
↓
3.タイマー処理にて
タイマー終了フラグを確認
タイマー終了フラグがFALSE(未終了)ならば
進捗率を確認
①進捗率が100になったらタイマー終了フラグをTURE(終了)に変更。②進捗率が100になっていなかった場合
進捗率を10インクリメントして、次のタイマータイミングで再確認。
タイマー終了フラグがTRUE(終了)ならば
タイマーを停止し、Form2をクローズする。
↓
2に戻る。(For文処理をし続ける。)
*************************************************************************************************************
Form1.cs
public partial class MainForm : Form {private int iValue = 0;
private bool bEnd = false;
private Progress clsProgress = null;public MainForm()
{
InitializeComponent();
/// タイマーのインターバル時間
this.tmProgressCount.Interval = 5;
}/// <summary>
/// 表示開始ボタン
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void button1_Click(object sender, EventArgs e) {/// ボタン押下後に動きっぱなしにするためFORをを使用しています。
/// 100000は適当に設定しています。
for(int iCount = 0; iCount < 100000; iCount++) {
Thread.Sleep(100);
if(this.bLoopEnd) {
break;
}
/// タイマースタート
this.tmProgressCount.Start();
/// プログレスバーの初期化
this.clsProgress = new Progress();
this.clsProgress.iProgress = 0;
this.iValue = 0;
this.bEnd = false;
/// プログレスバー(Form2)を表示
this.clsProgress.ShowDialog(this);
}
}/// <summary>
/// タイマー処理
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void tmProgressCount_Tick(object sender, EventArgs e) {/// タイマー終了フラグを確認する。
if (!this.bEnd) {
/// 進捗が100になったかを確認。
if (iValue == 100) {
// タイマー終了フラグを変更
this.bEnd = true;
} else {
/// 進捗が100になっていなければ10インクリメントして
/// プログレスバーに設定する。
iValue += 10;
this.clsProgress.iProgress = iValue;
}
} else {
/// タイマー処理を終了する。
this.tmProgressCount.Stop();
/// プログレスバーを閉じる。
this.clsProgress.Close();
}
}****************************************************************************************************************
Form2.cspublic partial class Progress : Form {
public Progress()
{
InitializeComponent();
}
/// <summary>
/// プログレスバーの進捗状況を格納します。
/// </summary>
public int iProgress{
set{
/// Max値を超える場合はMax値に丸める。
if (value > this.progressBar1.Maximum) {
this.progressBar1.Value = 100;
} else {
this.progressBar1.Value = value;
}
}
}
**************************************************************************************************************** -
nadeshikoさん、こんにちは!(^^)!ふ~です。
本日の11時に私も試験開始しました。12時~24時ですので、気の長い話です。
Code Snippetprivate void button1_Click(object sender, EventArgs e)
{
// ボタン押下後に動きっぱなしにするためFORをを使用しています。
// 100000は適当に設定しています。
for(int iCount = 0; iCount < 100000; iCount++) {// 処理時間を測定する
DateTime startTime = DateTime.Now;Thread.Sleep(100);
//if(this.bEnd) {
// break;
//}// タイマースタート
this.tmProgressCount.Start();// プログレスバーの初期化
this.clsProgress = new Progress();
this.clsProgress.iProgress = 0;
this.iValue = 0;
this.bEnd = false;// プログレスバー(Form2)を表示
this.clsProgress.ShowDialog(this);TimeSpan diff = DateTime.Now - startTime;
Debug.WriteLine("処理時間=" + (diff.Ticks / 10000) + " ms");
// 使用メモリを表示する
Debug.WriteLine(System.GC.GetTotalMemory(false).ToString()+" byte");
}
}処理時間の変化と、メモリ使用量の変化を表示しながら、デバッグーモードで実験しております。まだ、35分ですが明日どうなっているかが楽しみです。メモリ使用量の変化は650,000バイト~1,550,000バイトの範囲で増減しています。処理時間は328ms一定の速度で表示中です。
-
おはようございます。!(^^)!ふ~です。
原因は、仮想タイマーなどのリソースを使い切ってしまい使用出来なくなるようです。連続運転させる為には、タイマーも、Form2も使い続ける事で、内部リソースの消費を抑える事が必要と思われます。
Code Snippet<修正版その1:100000回テスト>
private void button1_Click(object sender, EventArgs e)
{// プログレスバーの初期化
this.clsProgress = new Progress();// タイマースタート
this.tmProgressCount.Start();
// ボタン押下後に動きっぱなしにするためFORをを使用しています。
// 100000は適当に設定しています。
for(int iCount = 0; iCount < 100000; iCount++) {// 処理時間を測定する
DateTime startTime = DateTime.Now;// プログレスバーの初期化
this.clsProgress.iProgress = 0;
this.iValue = 0;
this.bEnd = false;// プログレスバー(Form2)を表示
this.clsProgress.ShowDialog(this);TimeSpan diff = DateTime.Now - startTime;
Debug.WriteLine("処理時間=" + (diff.Ticks / 10000) + " ms");// 使用メモリを表示する
Debug.WriteLine(System.GC.GetTotalMemory(false).ToString()+" byte");}
// タイマー処理を終了する。
this.tmProgressCount.Stop();
}private void timer1_Tick(object sender, EventArgs e)
{// clsProgressインスタンスが有るか?
if (clsProgress == null) return;
// タイマー終了フラグを確認する。
if (!this.bEnd) {
// 進捗が100になったかを確認。
if (iValue == 100) {
// タイマー終了フラグを変更
this.bEnd = true;
} else {
// 進捗が100になっていなければ10インクリメントして
// プログレスバーに設定する。
iValue += 10;
this.clsProgress.iProgress = iValue;
}
} else {
// プログレスバーを閉じる。
this.clsProgress.Hide();
}
Debug.WriteLine("タイマー処理 発生");
}
}この様な修正を加え、取り合えず、リソース消費に観点を置いて実験中です。明日が楽しみです。
-
おはようございます!(^^)!ふ~です。
どうも、プログレスバーは真っ黒です。残念。this.clsProgress.ShowDialog(this)とthis.clsProgress.Hide()の繰り返しに問題がある(仮定)のでは?
そこで、Fom2を表示した状態で、プログレスバーのみ連続表示で問題は無い事を確認したいと思います。
namespace WinProgressCountTest
{
public partial class Form1 : Form
{
private int iValue = 0;
private bool bEnd = false;
private Progress clsProgress = null;
private long lCount = 0L; // タイマーカウンターpublic Form1()
{
InitializeComponent();// タイマーのインターバル時間
this.tmProgressCount.Interval = 5;
}private void button1_Click(object sender, EventArgs e)
{// タイマースタート
this.tmProgressCount.Start();// プログレスバーの初期化
this.clsProgress = new Progress();
this.clsProgress.iProgress = 0;
this.iValue = 0;
this.bEnd = false;// プログレスバー(Form2)を表示
this.clsProgress.ShowDialog(this);
}private void timer1_Tick(object sender, EventArgs e)
{
// Form2のインスタンスが無い場合
if (clsProgress == null) return;// 処理時間を測定する
DateTime startTime = DateTime.Now;
// タイマー終了フラグを確認する。
if (!this.bEnd) {
// 進捗が100になったかを確認。
if (iValue == 100) {
// タイマー終了フラグを変更
this.bEnd = true;} else {
// 進捗が100になっていなければ10インクリメントして
// プログレスバーに設定する。
iValue += 10;
this.clsProgress.iProgress = iValue;
}
} else {
// プログレスバーをクリアする。
this.iValue = 0;
this.clsProgress.iProgress = iValue;
this.bEnd = false;
}
lCount++;
Debug.WriteLine("タイマー処理 発生回数=" + lCount.ToString());
TimeSpan diff = DateTime.Now - startTime;
Debug.WriteLine("処理時間=" + (diff.Ticks / 10000) + " ms");
// 使用メモリを表示する
Debug.WriteLine(System.GC.GetTotalMemory(false).ToString()+" byte");
}
}
}また、明日どうなるか楽しみです。
-
こんにちは!(^^)!ふ~です。
プログレスバーだけの試験は、簡単に100000回を超えてしまいました。これにフォームの表示、非表示を加え、平均的に動作するように、ガベージコレクション処理を加えると、問題無く動作しております。
<連続動作可能なソース>
namespace WinProgressCountTest
{
public partial class Form1 : Form
{
private int iValue = 0;
private bool bEnd = false;
private Progress clsProgress = null;
private long lCount = 0L; // タイマーカウンターpublic Form1()
{
InitializeComponent();// タイマーのインターバル時間
this.tmProgressCount.Interval = 5;
}private void button1_Click(object sender, EventArgs e)
{// タイマースタート
this.tmProgressCount.Start();// プログレスバーの初期化
this.clsProgress = new Progress();
this.clsProgress.iProgress = 0;
this.iValue = 0;
this.bEnd = false;// プログレスバー(Form2)を表示
this.clsProgress.ShowDialog(this);}
private void timer1_Tick(object sender, EventArgs e)
{
// Form2のインスタンスが無い場合
if (clsProgress == null) return;// 処理時間を測定する
DateTime startTime = DateTime.Now;
// タイマー終了フラグを確認する。
if (!this.bEnd) {
// 進捗が100になったかを確認。
if (iValue == 100) {
// タイマー終了フラグを変更
this.bEnd = true;// Form2を隠す
this.clsProgress.Hide();// ガベージコレクションを行う。
GC.Collect();} else {
// 進捗が100になっていなければ10インクリメントして
// プログレスバーに設定する。
iValue += 10;
this.clsProgress.iProgress = iValue;
}
} else {
// プログレスバーをクリアする。
this.iValue = 0;
this.clsProgress.iProgress = iValue;
this.bEnd = false;// Form2を表示する
this.clsProgress.Show();
}lCount++;
Debug.WriteLine("タイマー処理 発生回数=" + lCount.ToString());
TimeSpan diff = DateTime.Now - startTime;
Debug.WriteLine("処理時間=" + (diff.Ticks / 10000) + " ms");
// 使用メモリを表示する
Debug.WriteLine(System.GC.GetTotalMemory(false).ToString()+" byte");// 終了判断条件
if (100000L < lCount)
{
// タイマースタート
this.tmProgressCount.Stop();// Form2クローズする
this.clsProgress.Close();Debug.WriteLine("お疲れ様です。無事、耐久試験完了致しました。");
}
}
}
}◇[まとめ]
繰り返しに向かない組み合わせ
1)this.clsProgress.ShowDialog(this) と this.clsProgress.Hide()
2)new() と this.clsProgress.ShowDialog(this) と this.clsProgress.Close()
連続繰り返しに耐える組み合わせ
1)this.clsProgress.Show() と this.clsProgress.Hide() (息継ぎが有る)
2)this.clsProgress.Show() と this.clsProgress.Hide() と GC.Collect() (平均安定動作)
フォーム2の表示速度も.Show()とHide() が圧倒的に速いです。C#でも、用途にあわせて、メソッドを選ばないと性能がでないようです。ご参考になれば幸いです。