- - PR -
スタックオーバーフローを防ぐ方法について
投稿者 | 投稿内容 | ||||
---|---|---|---|---|---|
|
投稿日時: 2008-03-11 14:29
WinXP + VB.NET 2005 + シリアルI/O によるハードの制御を行うPGを作成しているのですが、ループがスタックを食いつぶしてしまい、スタックオーバーフローを発生させてしまって困っています。どなたかわかる方がいらっしゃいましたら、お知恵をお貸しください。
現象は、実行開始から20時間ほどでスタックオーバーフローが発生し、スレッドが落ちてしまうというもので、プログラム自体はWinodwsサービスとし作成してあります。 現象が発生するのは以下の部分で、シリアルポートは前段階で開いたままになっています。また、サービスのスレッドとは別スレッドで動作しているので、スタックオーバーフローが起きても、サービス自体は生きています。 ************************************ DO IF 割り込み命令が存在すれば THEN 変数 = 割り込み命令文 ELSE 変数 = 生存確認文 END IF シリアルで『変数』送信 try シリアルで受信 catch シリアル通信がタイムアウト、もしくは返信文異常で エラーログ書き出し。 end try LOOP サービスの停止が無ければ ************************************ 明らかにloopがスタックを食いつぶしているのはわかっているのですが、常に通信をまわしておく必要があるため、タイマースレッド等では要件を満たせず、もしかしたらVBがスタックを巧くやりくりしてくれるかも??っと淡い期待をもって書いてみましたが、やはりNGで困りはてています。 タイマースレッドで1ミリ秒間隔でやればいいのでは?っと思われると思いますが、 ハード側がその1ミリ秒が待てないガマンできない子で、しかも通信レスポンスの速度を求められています。速度を犠牲にせず、スタックオーバーフローを防ぐ手法のアイディアをお持ちのかたがいらっしゃいましたら、是非おしえてください!! ※必要な情報があればわかる範囲であげさせていただきますので、ご指示ください。 | ||||
|
投稿日時: 2008-03-11 14:43
見る限りでは問題なさそうなので
もう少しコメントアウトして原因を限定した方がよいのでは 例)送受信はコメントアウトして放置する 例)try-catchをとる | ||||
|
投稿日時: 2008-03-11 15:01
>>indigo-xさん
返信ありがとうございます。 >例)送受信はコメントアウトして放置する >例)try-catchをとる 残念ながら、既に試行済みでした。 エラーまでの時間が伸びはするものの、エラー自体は間違いなく発生してしまいます。 サービスが停まるまで単純に無限ループしてしまうため、どうしてもこのコーディングではスタックオーバーフローが発生してしまう様子です。 | ||||
|
投稿日時: 2008-03-11 15:21
答えでなくてごめん。 WindowsXP(たぶんProfessional?)で、リアルタイム処理ってできたっけ? 1ミリ秒タイマーですら待てないのならこっちのOSとか、リアルタイム処理をサポートしたものを検討してみてはいかがかな? http://www.microsoft.com/japan/windows/embedded/techinsights/realtime.mspx [追記] って、さらにごめん。 引用部分にだけ反応してリアルタイムOSとか書いちゃったけど、 対応してる開発ツールで作り直す手間とか考えてなかった。脱線させてすまない。 [/追記] [ メッセージ編集済み 編集者: どせい 編集日時 2008-03-11 15:32 ] | ||||
|
投稿日時: 2008-03-11 15:54
>>どせいさん
お返事ありがとうございます。 Motherシリーズを思い出してしまうかわいい名前ですねw リアルタイムOSはむしろ「つかいたい」です(泣) この仕事請けた時点ではそんな用件もなく、「VBで軽く作っておわそうぜ」な感じで請けたのですが、ふたを開けたら最後に困った要件が挙がってしまった感じです。 おっしゃることは正論ですが、大人の理由でいまさら返られないという良くあるアレです・・・ 変えられるなら変えたい(号泣) | ||||
|
投稿日時: 2008-03-11 16:02
この「変数」はStringだと思いますが、StringBuilderクラスを使用してはどうでしょうか。 String オブジェクトを変更するように見えるメソッドは、実際には変更内容が反映された新しい String オブジェクトを返します。 ↑この辺がオーバーフローを発生させていると眼力 | ||||
|
投稿日時: 2008-03-11 16:07
スタックオーバーフローはコールスタックがオーバーフローしているのでしょうか?すなわち、メソッド呼び出しが多重にネストしているのでしょうか?だとしたら、意図せず再帰呼び出しのようなことをしているのかもしれず、もしそうであれば複雑なグラフ探索などでないかぎり、プログラムの間違いであることがほとんどでしょう。 ソースコード中で再帰呼び出しになる可能性はあるのでしょうか?(まったくない、少しある、再帰を前提として作ってある、etc.) それともデーターのスタックがオーバーフローしているのでしょうか?C/C++ ならばそういうこともあるのかもしれませんが、今はスタック領域をデーターに使うということはほとんどないため、これは少ないと思います。 スタックオーバーフローする少し手前で、プログラムの実行をブレーク(一時停止)した場合、呼び出し履歴は多重になってはいないのでしょうか?サービスということなのでデバッグが難しいかもしれませんが。ちなみにサービスでなければこのエラーにはならないのでしょうか? | ||||
|
投稿日時: 2008-03-11 16:11
そうですか、更にコメントアウト可能であればしてみてはどうですか?
スタックオーバーフローは考え難いですね。 (考えられるのはDLLImportとかして引数が多いとか?) その他の対策案として ・最後の手段は、最小限なコードにしてアセンブリコードを確認する? ・C#orC++/CLIに書き直す(VB.NETとコンパイラーが違うので) ・C言語で書いてVB.NETから呼び出す等 ・24時間稼動でなければ10時間毎にこっそりスレッド入替える (おそらく100msぐらいで入替え完了すると思います) 参考になればと思います。 |