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

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

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

Re[9]: 再帰によるスタックオーバフローエラー


(過去ログ 47 を表示中)

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

■25671 / inTopicNo.1)  再帰によるスタックオーバフローエラー
  
□投稿者/ Lily (1回)-(2008/09/24(Wed) 15:12:11)

分類:[VB.NET/VB2005 以降] 

Microsoft Development Environment 2003
Microsoft .NET Framework 1.1
Microsoft Visual Basic .NET

現在上記の環境にて、Microsoft Wordに対するアドオンを作成しています。

タイトルにあるとおり、再帰処理にて、スタックオーバフローエラーが表示されます。
--------------------------------------------------------------------------------------------
'System.StackOverflowException' のハンドルされていない例外が system.dll で発生しました。
--------------------------------------------------------------------------------------------
別バージョン
--------------------------------------------------------------------------------------------
'System.StackOverflowException' のハンドルされていない例外が mscorlib.dll で発生しました。
--------------------------------------------------------------------------------------------


Word文書に対する内容から再帰の処理が組み立てられるため、
再帰の数はとても大きくなる可能性が有りえます。

有る程度の再帰処理(数万)なら、処理は正常に終了します。


そこで、質問なんですが
【1】スタックのサイズは変更できるのでしょうか?
<http://q.hatena.ne.jp/1138609105>にて、変更できそうな感じがしたので。
   また、最終的にはWordアドオンとしてユーザに配布するので、クライアント毎に設定は難しいです。

【2】一概には言えないと思いますが、処理の見直しのポイントを教えてください。
   ※メモリ解放をすれば直るよとか・・


よろしくお願いします。

引用返信 編集キー/
■25679 / inTopicNo.2)  Re[1]: 再帰によるスタックオーバフローエラー
□投稿者/ たくボン (31回)-(2008/09/24(Wed) 15:35:19)
No25671 (Lily さん) に返信
> Microsoft Development Environment 2003
> 【1】スタックのサイズは変更できるのでしょうか?
> <http://q.hatena.ne.jp/1138609105>にて、変更できそうな感じがしたので。

参照できないのですが?


> 【2】一概には言えないと思いますが、処理の見直しのポイントを教えてください。
処理の内容が曖昧なのに見直しのポイントと言われても、回答しにくいと思います。
もう少し概要でもわかれば回答できると思いますが・・・。

特に、今回のStackOverflowExceptionは、VS2003(VB)+.NET1.1ならtry〜catchとif文でも発生した経験があるので、回答しにくい部分だと思います。
引用返信 編集キー/
■25681 / inTopicNo.3)  Re[1]: 再帰によるスタックオーバフローエラー
□投稿者/ 渋木宏明(ひどり) (893回)-(2008/09/24(Wed) 15:37:18)
渋木宏明(ひどり) さんの Web サイト
> 【1】スタックのサイズは変更できるのでしょうか?

出来るけど、「あとのほんのちょっと延命できれば十分」な場合以外、あまり賢い解決とは言えません。

> 【2】一概には言えないと思いますが、処理の見直しのポイントを教えてください。

再帰をループに書き直すのがもっとも強靭な解です。

あるいは、再帰するにしても中間状態の保存をスタックに頼るのではなく、List<T> などを使って自前でコンテキストを管理するようにする、とかです。

引用返信 編集キー/
■25682 / inTopicNo.4)  Re[2]: 再帰によるスタックオーバフローエラー
□投稿者/ 渋木宏明(ひどり) (894回)-(2008/09/24(Wed) 15:39:53)
渋木宏明(ひどり) さんの Web サイト
> 特に、今回のStackOverflowExceptionは、VS2003(VB)+.NET1.1ならtry〜catchとif文でも発生した経験があるので、回答しにくい部分だと思います。

そりゃ、再帰の深度がとかゆう話ではなくて

int Hoge
{
get { return this.Hoge; }
}

みたいなウッカリ系の場合じゃなくて?
引用返信 編集キー/
■25686 / inTopicNo.5)  Re[3]: 再帰によるスタックオーバフローエラー
□投稿者/ PATIO (124回)-(2008/09/24(Wed) 15:47:03)
賛否両論はあると思いますけれど、
私の認識だと再帰処理で旨くこなせるのは、再帰の深さが無制限に大きくなるようなケースがなく、
かつ、一つ一つの処理が軽く、各処理毎に大きなメモリ領域を確保するような処理を行なわないケースだと
思っているので、大量データを処理したいようなケースには初めから向いていないと考えています。

むしろ、小規模な有限データを対象に一つの処理は軽いんだけど深さが伴うようなケースだと
思います。処理の過程でスタックオーバーフローが発生してしまうような規模を扱う可能性がある時点で
再帰処理を使うには向かない処理だと思います。

引用返信 編集キー/
■25687 / inTopicNo.6)  Re[2]: 再帰によるスタックオーバフローエラー
□投稿者/ επιστημη (1336回)-(2008/09/24(Wed) 15:47:20)
επιστημη さんの Web サイト
>>【2】一概には言えないと思いますが、処理の見直しのポイントを教えてください。
>...
> あるいは、再帰するにしても中間状態の保存をスタックに頼るのではなく、
> List<T> などを使って自前でコンテキストを管理するようにする、とかです。

あとはローカル変数を極力減らす。
スタック消費量 ≒ (ローカル変数の総サイズ+α)×再帰の深さ

引用返信 編集キー/
■25689 / inTopicNo.7)  Re[3]: 再帰によるスタックオーバフローエラー
□投稿者/ たくボン (32回)-(2008/09/24(Wed) 15:58:15)
No25682 (渋木宏明(ひどり) さん) に返信
>>特に、今回のStackOverflowExceptionは、VS2003(VB)+.NET1.1ならtry〜catchとif文でも発生した経験があるので、> > int Hoge
> {
>   get { return this.Hoge; }
> }
> 
> みたいなウッカリ系の場合じゃなくて?

違いますね。
Try
  If hoge = xxx Then Exit Sub
Catch ex As Exception
  hogehoge
End Try
のように、If文を1行で書いた場合に発生してました。
MSにも報告してfixされたので現在はないと思いますが、最新でない場合はSPを適用するのが良いかと。

引用返信 編集キー/
■25694 / inTopicNo.8)  Re[2]: 再帰によるスタックオーバフローエラー
□投稿者/ Lily (3回)-(2008/09/24(Wed) 16:15:59)
No25679 (たくボン さん) に返信
> 参照できないのですが?
すいません。最後の>がURLに含まれていました。
http://q.hatena.ne.jp/1138609105
です。

> 処理の内容が曖昧なのに見直しのポイントと言われても、回答しにくいと思います。
> もう少し概要でもわかれば回答できると思いますが・・・。
そうですよね。
実際エラーが表示される部分は、正規表現を使用してローカル変数に値を組み込む場合や
配列を作成している場合にエラーになっています。

ただ、もちろん処理を変更するとエラー箇所が変わるため根本的に見直しが必要かと思いますが。


引用返信 編集キー/
■25695 / inTopicNo.9)  Re[4]: 再帰によるスタックオーバフローエラー
□投稿者/ Lily (4回)-(2008/09/24(Wed) 16:26:13)
No25679 (たくボン さん) に返信
> 参照できないのですが?
すいません。最後の>がURLに含まれていました。
http://q.hatena.ne.jp/1138609105
です。

> 処理の内容が曖昧なのに見直しのポイントと言われても、回答しにくいと思います。
> もう少し概要でもわかれば回答できると思いますが・・・。
そうですよね。
実際エラーが表示される部分は、正規表現を使用してローカル変数に値を組み込む場合や
配列を作成している場合にエラーになっています。

ただ、もちろん処理を変更するとエラー箇所が変わるため根本的に見直しが必要かと思いますが。


#こちらのネットワークの関係で、直ぐに書込むことが出来ませんがよろしくお願いします。

引用返信 編集キー/
■25698 / inTopicNo.10)  Re[4]: 再帰によるスタックオーバフローエラー
□投稿者/ 渋木宏明(ひどり) (895回)-(2008/09/24(Wed) 16:36:17)
渋木宏明(ひどり) さんの Web サイト
> のように、If文を1行で書いた場合に発生してました。

そらコンパイラのバグですよね。

コンパイラのバグじゃあ、StackOverflowException どころか、何が起こるか予測不能ですね。

引用返信 編集キー/
■25699 / inTopicNo.11)  Re[5]: 再帰によるスタックオーバフローエラー
□投稿者/ Lily (5回)-(2008/09/24(Wed) 16:40:23)
No25681 (渋木宏明(ひどり) さん) に返信
> 出来るけど、「あとのほんのちょっと延命できれば十分」な場合以外、あまり賢い解決とは言えません。
確かにそうですね。今の処理だと上限がないため完全な解決策とはいかなそうです。
出来れば、方法を教えていただけるとあり難いです。


> 再帰をループに書き直すのがもっとも強靭な解です。
> あるいは、再帰するにしても中間状態の保存をスタックに頼るのではなく、
> List<T> などを使って自前でコンテキストを管理するようにする、とかです。
最初の仕様では、再帰を行うことが一番の解決策であったため、再帰処理を使用したんですが、
今の仕様であれば、ループ処理でも可能です。ただ、大幅の改善が認められないと思うのでそこがネックですが・・・
引用返信 編集キー/
■25700 / inTopicNo.12)  Re[1]: 再帰によるスタックオーバフローエラー
□投稿者/ 長月葵 (32回)-(2008/09/24(Wed) 16:43:20)
長月葵 さんの Web サイト
No25671 (Lily さん) に返信
 そもそも再帰である必要ありますか?
 再帰である必要がありそうならばなぜそう思いましたか?
 再帰である必要がなさそうならば再帰しない処理への変更は難しいことですか?
 再帰である必要がなさそうで再帰しない処理への変更が難しい場合どのように難しいと感じましたか?
引用返信 編集キー/
■25701 / inTopicNo.13)  Re[6]: 再帰によるスタックオーバフローエラー
□投稿者/ 長月葵 (33回)-(2008/09/24(Wed) 16:49:44)
長月葵 さんの Web サイト
 書いてる間に返信きてたorz

No25699 (Lily さん) に返信
> ■No25681 (渋木宏明(ひどり) さん) に返信
> 出来れば、方法を教えていただけるとあり難いです。
 どういった形で再帰処理をしてますか?
 そのもののソースではなくてよいのでこんな感じと言うコードを示してもらえると答えやすいです。

>>再帰をループに書き直すのがもっとも強靭な解です。
>>あるいは、再帰するにしても中間状態の保存をスタックに頼るのではなく、
>>List<T> などを使って自前でコンテキストを管理するようにする、とかです。
> 最初の仕様では、再帰を行うことが一番の解決策であったため、再帰処理を使用したんですが、
> 今の仕様であれば、ループ処理でも可能です。ただ、大幅の改善が認められないと思うのでそこがネックですが・・・
「大幅の改善が認められない」と言うのはループ処理に変更してもスタックオーバーフローは発生しそうと言うことですか?
 それとも何らかのパフォーマンスについての言及ですか?
引用返信 編集キー/
■25706 / inTopicNo.14)  Re[6]: 再帰によるスタックオーバフローエラー
□投稿者/ PATIO (125回)-(2008/09/24(Wed) 17:15:05)
No25699 (Lily さん) に返信
>>再帰をループに書き直すのがもっとも強靭な解です。
>>あるいは、再帰するにしても中間状態の保存をスタックに頼るのではなく、
>>List<T> などを使って自前でコンテキストを管理するようにする、とかです。
> 最初の仕様では、再帰を行うことが一番の解決策であったため、再帰処理を使用したんですが、
> 今の仕様であれば、ループ処理でも可能です。ただ、大幅の改善が認められないと思うのでそこがネックですが・・・

大幅な改善と言うのが何を指しているのかが気になります。
再帰処理はコードのコンパクト化には役立つと思いますが、わかり易いかと言われると首を傾げますし、
通常のループ処理よりもパフォーマンスが出るかと言うとそんな事は無いと思います。
(パフォーマンスが出る出ないは再帰処理とは別の話ではないかなと思います)
通常のループ処理の方がスタックオーバーフローは置きにくいし、何よりもコードがわかりやすいと
言うのは大きな利点ではないでしょうか。
(まあ、組み方が悪ければどちらでも同じでしょうけれど)

引用返信 編集キー/
■25715 / inTopicNo.15)  Re[7]: 再帰によるスタックオーバフローエラー
□投稿者/ Lily (6回)-(2008/09/24(Wed) 18:17:43)
No25701 (長月葵 さん) に返信
>  どういった形で再帰処理をしてますか?
>  そのもののソースではなくてよいのでこんな感じと言うコードを示してもらえると答えやすいです。


最終的には、下記のような数字の組み合わせを表示する
プログラムを作成しています。(多い場合は、5千行以上)
-------------------------------------------------
 1
 1 - 2
 1 - 2 - 3
 1 - 2 - 3 - 4
 1 - 2 - 3 - 5
 1 - 3
 1 - 3 - 4
 2
-------------------------------------------------
    大分省略しましたが、こんな感じです。
    PubTreeTblというDataTableに値が格納されている
    PubClaimBodyに結果を書込み(実際は、下記ソースにてDataTableに値を保存している。)

    Private Sub MakeOutPut()
        ' ************************************************************************
        '   機能:  出力用DataTable作成(PubSenteTreeTbl)
        ' ************************************************************************
        For rowCnt As Integer = 0 To PubTreeTbl.Rows.Count - 1
            ' No取得
            PubClaimNo = PubTreeTbl.Rows(rowCnt).Item("No")
            If PubTreeTbl.Rows(rowCnt).Item("Flg") = True Then
                ' 最大桁数によって、左側にスペースを追加
                PubClaimBody = PubTreeTbl.Rows(rowCnt).Item("No").ToString.PadLeft(MaxFigure)
                Call ClaimReflexive(rowCnt)
            End If
        Next
    End Sub

    Private Sub ClaimReflexive(ByVal rowCnt As Integer)
        ' ************************************************************************
        '   機能:  再帰処理
        ' ************************************************************************
        Dim ClaimArray() As String = Split(PubTreeTbl.Rows(rowCnt).Item("List"), ",")
        If ClaimArray.Length >= PubAryPos(rowCnt) Then
            If ClaimArray(PubAryPos(rowCnt) - 1) <> "" Then
                ' クレームNo取得
                PubSubClaimNo = Integer.Parse(ClaimArray(PubAryPos(rowCnt) - 1))
                PubClaimBody += "-" & PubSubClaimNo.ToString.PadLeft(MaxFigure)
            Else
                ' ツリーの値が取れなかった場合
                If ClaimBeforeReflexive(rowCnt) = False Then
                    Exit Sub
                End If
            End If
        Else
            ' ツリーの値が取れなかった場合
            If ClaimBeforeReflexive(rowCnt) = False Then
                Exit Sub
            End If
        End If
        ' 再帰
        Call ClaimReflexive(PubSubClaimNo - 1)
    End Sub

    Private Function ClaimBeforeReflexive(ByVal rowCnt As Integer)
        ' クレームツリーの前の数値を取得
        PubSubClaimNo = PubAryPla(rowCnt)

        ' 終了条件
        If PubSubClaimNo = 0 Then
            ClaimBeforeReflexive = False
            Exit Function
        End If
        ' ツリーの最後を削除
        PubClaimBody = Regex.Replace(PubClaimBody, "-(?!.*-).*([0-90-9]*)", "")
        ClaimBeforeReflexive = True
    End Function



> 「大幅の改善が認められない」と言うのはループ処理に変更してもスタックオーバーフローは発生しそうと言うことですか?
>  それとも何らかのパフォーマンスについての言及ですか?
すいません。こちらの都合です。
実は、テスト等が終っている状態で大きなプログラムの修正が認められないということです。



引用返信 編集キー/
■25716 / inTopicNo.16)  Re[8]: 再帰によるスタックオーバフローエラー
□投稿者/ れい (800回)-(2008/09/24(Wed) 20:01:01)
No25715 (Lily さん) に返信
>>「大幅の改善が認められない」と言うのはループ処理に変更してもスタックオーバーフローは発生しそうと言うことですか?
>> それとも何らかのパフォーマンスについての言及ですか?
> すいません。こちらの都合です。
> 実は、テスト等が終っている状態で大きなプログラムの修正が認められないということです。

再帰がどのくらいの深さになるのか、
見積もりが甘かったと言うことですから
プログラムを大幅に修正することになっても仕方ないですね。

テストもやり直しが順当で。
動かないプログラムを修正できないほうがおかしいかと。

なんとかごまかすなら…

正規表現はスタックをたくさん消費しますので、再帰内では避けるとか。
避けることができなくても、せめてインスタンスを作成してコンパイルしておくとか。
ClaimReflexiveは簡単な末尾再帰なのでこれだけでも展開するとか。
引用返信 編集キー/
■25730 / inTopicNo.17)  Re[8]: 再帰によるスタックオーバフローエラー
□投稿者/ PATIO (126回)-(2008/09/25(Thu) 10:42:24)
No25715 (Lily さん) に返信

> すいません。こちらの都合です。
> 実は、テスト等が終っている状態で大きなプログラムの修正が認められないということです。

うーん、気持ちはわかるんですが。
例えば、スタックオーバーフローがでない事を現状では保障出来ないと思います。
皆さんが書かれているローカル変数の減らす、スタックの消費が激しい処理の見直しをする、
もしくはあまり感心しませんが、スタックのサイズを増やすという事を行っても
再帰処理を使っている以上、スタックオーバーフローが起こる可能性は回避できません。
それでも納入先が納得してくれるならそれはそれで仕様と言う話になると思いますが、
それに関しては御本人を含めた会社の話になると思うので何とも言えません。

で、結論としては保証できるレベルでの回避は不可能と言うのが結論だと思います。
あと、どうするかは会社で話し合われる事をお勧めします。

引用返信 編集キー/
■25732 / inTopicNo.18)  Re[7]: 再帰によるスタックオーバフローエラー
□投稿者/ PATIO (127回)-(2008/09/25(Thu) 10:45:48)
あうあう。

> 例えば、スタックオーバーフローがでない事を現状では保障出来ないと思います。

ここの「例えば、」は意味が無いので無視してください。
修正が出来なくなったのでつらいです。
まあ、書き込む前に見直せと言うのはごもっともな話なのですが。

引用返信 編集キー/
■25736 / inTopicNo.19)  Re[9]: 再帰によるスタックオーバフローエラー
□投稿者/ Lily (7回)-(2008/09/25(Thu) 11:53:14)
No25730 (PATIO さん) に返信
> で、結論としては保証できるレベルでの回避は不可能と言うのが結論だと思います。
> あと、どうするかは会社で話し合われる事をお勧めします。

回答ありがとうございます。
確かにその通りだと思います。今、先方とその点について話し合いを進めております。


> もしくはあまり感心しませんが、スタックのサイズを増やすという事を行っても
> 再帰処理を使っている以上、スタックオーバーフローが起こる可能性は回避できません。

どなたか、スタックサイズの増加方法を教えて下さい。(参考URLでもお願いします。)
コードの修正と併せて対応しようと思っております。

よろしくお願いします(>_<)
引用返信 編集キー/
■25738 / inTopicNo.20)  Re[10]: 再帰によるスタックオーバフローエラー
 
□投稿者/ たくボン (35回)-(2008/09/25(Thu) 12:07:47)
No25736 (Lily さん) に返信
> ■No25730 (PATIO さん) に返信
> どなたか、スタックサイズの増加方法を教えて下さい。(参考URLでもお願いします。)

editbin.exeで良いならここに資料があります。

MSのページならここ
http://msdn.microsoft.com/ja-jp/library/xd3shwhf(VS.80).aspx

簡潔にまとめてくれているのはここ
http://www.xlsoft.com/jp/products/intel/cvf/docs/vf-html/pg/pg26_09.htm

注:C++を入れてないと入ってないかもしれません。
引用返信 編集キー/

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

管理者用

- Child Tree -