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

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

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

C# MVC でのスタックオーバーフロー

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

■85038 / inTopicNo.1)  C# MVC でのスタックオーバーフロー
  
□投稿者/ はな (1回)-(2017/09/06(Wed) 15:56:52)

分類:[C#] 

C# MVCから参照するDLLでスタックオーバーフローが発生して困っています。

参照するDLLは二つあり、片方はスタックオーバーフローせず、片方はスタックオーバーフローします。
xxx.dll・・・オーバーフローしてしまう。スタック回数は1000回程度だが、300ほどでオーバーフロー。
yyy.dll・・・オーバーフローしない。スタック回数10000回以上

この二つのDLLをコンソールアプリケーションから参照した場合にはどちらもスタックオーバーフローしません。

xxx.dllとyyy.dllでなにが違うのか?どこを調べるべきか?
MVCとコンソールアプリケーションで何が違うのか?どこを調べるべきか?

よろしくお願いいたします。
引用返信 編集キー/
■85040 / inTopicNo.2)  Re[1]: C# MVC でのスタックオーバーフロー
□投稿者/ WebSurfer (1298回)-(2017/09/06(Wed) 16:43:07)
No85038 (はな さん) に返信
> C# MVCから参照するDLLでスタックオーバーフローが発生して困っています。

何を作っているのですか? ASP.NET MVC アプリ?

あと、開発環境・運用環境が不明です。

他にも不明点が多々ありますが、それら 2 つは質問するときに最低限書くべきことなのですが・・・


引用返信 編集キー/
■85041 / inTopicNo.3)  Re[2]: C# MVC でのスタックオーバーフロー
□投稿者/ はな (3回)-(2017/09/06(Wed) 17:22:58)
これは失礼しました。

開発環境はVisualStudio 2013です。
運用・・・とうか今はデバッグ実行で確認しています。

IISに乗せてもスタックオーバーフローは解決しません。
.NET Framework 4.0です。

ASP.NET MVC で作成しています。


コンソールアプリケーションはDLLの動作確認用にテスト的に作成したものです。



No85040 (WebSurfer さん) に返信
> ■No85038 (はな さん) に返信
>>C# MVCから参照するDLLでスタックオーバーフローが発生して困っています。
>
> 何を作っているのですか? ASP.NET MVC アプリ?
>
> あと、開発環境・運用環境が不明です。
>
> 他にも不明点が多々ありますが、それら 2 つは質問するときに最低限書くべきことなのですが・・・
>
>
引用返信 編集キー/
■85042 / inTopicNo.4)  Re[3]: C# MVC でのスタックオーバーフロー
□投稿者/ ぶなっぷ (124回)-(2017/09/06(Wed) 18:25:21)
スタックオーバーフローは私の経験上、ほとんどの場合が、
・巨大配列のnew
・深すぎる(または無限)再帰呼び出し
でした。

前者はコレクション使ってれば起きないはずなんで、
一般的なコードなら後者でしょう。

 1) 再帰呼び出しの抜け口がなくなってしまうパターンがないか?
 2) ツリーなどを再帰呼び出しで操作していて、ツリーが深すぎないか?

私の場合、過去に2)ではまって、
再帰コードを非再帰コードに書き換えたことがあります。

理論的に、再帰コードは非再帰コードに書き換えられることが保証されています。

引用返信 編集キー/
■85043 / inTopicNo.5)  Re[3]: C# MVC でのスタックオーバーフロー
□投稿者/ WebSurfer (1299回)-(2017/09/06(Wed) 19:21:00)
No85041 (はな さん) に返信

私のレスを全文引用してますが、引用は必要最小限にとどめてください。見難くなります。

> 参照するDLLは二つあり、片方はスタックオーバーフローせず、片方はスタックオーバーフローします。
> xxx.dll・・・オーバーフローしてしまう。スタック回数は1000回程度だが、300ほどでオーバーフロー。
> yyy.dll・・・オーバーフローしない。スタック回数10000回以上

スタックオーバーフローとなるのはどのように確認したのでしょう?(失礼ながら、ホントに
スタックオーバーフルーなのかちょっと疑ってます)

「スタック回数」というのは何なのですか? メソッドの再帰呼び出しの深さのようなもので
深くなるほど(回数に比例して)スタックメモリの消費量が増えるのですか?

エラーが実際にスタックオーバーフローで、「スタック回数」に比例してスタック消費量が増え
るということであれば、自分が想像できるのは、

> この二つのDLLをコンソールアプリケーションから参照した場合にはどちらもスタックオーバーフローしません。

ASP.NET Web アプリとコンソールアプリでは使用できるスタックのサイズが違うからだと思いま
す。それ以外に違いが出る原因は自分は思いつきません。

前者は 256KB という記事を見つけました。

Stack sizes in IIS &#8211; affects ASP.NET
https://blogs.msdn.microsoft.com/tom/2008/03/31/stack-sizes-in-iis-affects-asp-net/

後者は 1 MB だと思います。

Thread Stack Size
https://msdn.microsoft.com/en-us/library/windows/desktop/ms686774(v=vs.85).aspx

> xxx.dllとyyy.dllでなにが違うのか?どこを調べるべきか?

「スタック回数」の 1 回あたりのスタック消費量が違う(xxx.dll > yyy.dll)からではないかと
思います。そこを調べてみては?

以上は自分の想像です。これ以上のことは、今提供されている情報ではわかりません。

引用返信 編集キー/
■85048 / inTopicNo.6)  Re[4]: C# MVC でのスタックオーバーフロー
□投稿者/ はな (4回)-(2017/09/07(Thu) 11:02:04)
ぶなっぷさん、WebSurferさん貴重な情報ありがとうございます。

> スタックオーバーフローは私の経験上、ほとんどの場合が、
> ・巨大配列のnew
> ・深すぎる(または無限)再帰呼び出し
> でした。

巨大な2次元配列使ってます。

スタック領域の不足ではなく、連続したメモリ領域の確保ができない可能性があるということですね。
スタックオーバーフローエクセプションが出ていたので、スタック領域のことばかり考えていました。

お二方の情報を元に改修を考えて見ます。

解決済み
引用返信 編集キー/
■85049 / inTopicNo.7)  Re[5]: C# MVC でのスタックオーバーフロー
□投稿者/ なちゃ (218回)-(2017/09/07(Thu) 12:00:50)
巨大配列のnewでStackOverflowってあり得ますかね…?

同じコードで環境によるというのは、すでに出されてるとおりASP.NET環境のスタックサイズの違いによる影響の可能が高そうな気はしますが、
開発サーバやIIS Expressでも同様なのかはちょっと分かりません。

あとは普通にライブラリで再起やスタックサイズの消費が大きいメソッドがあるかですかね。
例えばソートとか、組み込みのグリッドのソート機能でスタックオーバーするようなこともあったりしますので、
必ずしも自コード上で明らかに再起などがあるとは限りません。

解決済み
引用返信 編集キー/
■85050 / inTopicNo.8)  Re[6]: C# MVC でのスタックオーバーフロー
□投稿者/ なちゃ (219回)-(2017/09/07(Thu) 12:04:55)
追加です。
開発環境でのデバッグ中なら、スタックオーバーしたときの例外情報とかでスタックトレース確認できないですかね?

ていうかちょっと未だにスタック回数の意味分かってないので、何か認識違いがある予感はしますが…
解決済み
引用返信 編集キー/
■85052 / inTopicNo.9)  Re[7]: C# MVC でのスタックオーバーフロー
□投稿者/ はな (5回)-(2017/09/07(Thu) 15:39:39)
返信ありがとうございます。

スタックの深さが300程度でスタックオーバーフローするのが腑に落ちないでいたのです。

スタックトレースで、300程度の呼び出し履歴になってます。

自前で関数の呼び出し回数(深度)を数えて「200を超えたら、いったん戻る」というようにコーディングすると最後まで計算できます。

処理の概要は
A1の値が知りたいときにA1の値を計算するために必要なほかの値を先に計算してからA1を求めるようなことをしてます。
A1=B1 + C1
B1=5
C1=B2 + D2
・・・
Excelでするような計算です。(計算式はユーザが自由に変更します)

呼び出し深度の計測でC200までいってしまったら、A1の計算を保留して、C200を先に計算して・・・
という方法で回避してますが速度的に厳しいのと、スタック領域が少ないのが腑に落ちなくて質問しました。
引用返信 編集キー/
■85053 / inTopicNo.10)  Re[8]: C# MVC でのスタックオーバーフロー
□投稿者/ ぶなっぷ (125回)-(2017/09/07(Thu) 15:49:35)
スタックはいろんな目的で使用されます。
・ローカル変数
・メソッドのコールスタック
・メソッドの引数
・メソッドの戻り値
    :

したがって、
> 巨大な2次元配列使ってます。
が再帰呼び出しされるメソッドのローカル変数なら、
比較的少ない再帰呼び出しでもスタックオーバーフローするはずです。

といいつつ、私の知識はC++時代のものなので、
C#だとメモリ確保の方法が違ってるかもです(^^;

引用返信 編集キー/
■85054 / inTopicNo.11)  Re[8]: C# MVC でのスタックオーバーフロー
□投稿者/ 魔界の仮面弁士 (1404回)-(2017/09/07(Thu) 16:27:41)
No85052 (はな さん) に返信
> スタックの深さが300程度でスタックオーバーフローするのが腑に落ちないでいたのです。

300で落ちるのが妥当なのかは、具体的なコードを見ていないので判断できませんが、
たとえば極端な例として、下記のようなコンソールアプリを用意してみたところ、
60 回までは耐えられますが、61 回目で StackOverflowException を吐きました。

public struct ST0 { public ST1 a, b, c, d; }
public struct ST1 { public ST2 a, b, c, d; }
public struct ST2 { public ST3 a, b, c, d; }
public struct ST3 { public ST4 a, b, c, d; }
public struct ST4 { public decimal a, b, c, d; }

class Program {
 static void Main() { Loop(300, default(ST0)); }
 static void Loop(int i, ST0 z) { if (i > 0) Loop(i - 1, z); }
}


なお、コンパイル後に
 editbin /STACK:4000000 "C:\…\ConsoleApplication1.exe"
とすれば、244 回までは耐えられるようになりますし、
/STACK:8000000 にすれば、488 回まで耐えられました。
引用返信 編集キー/
■85055 / inTopicNo.12)  Re[9]: C# MVC でのスタックオーバーフロー
□投稿者/ はな (6回)-(2017/09/07(Thu) 17:23:58)
> なお、コンパイル後に
>  editbin /STACK:4000000 "C:\…\ConsoleApplication1.exe"
> とすれば、244 回までは耐えられるようになりますし、
> /STACK:8000000 にすれば、488 回まで耐えられました。

C#のスタック領域変更が見つけられなかったので助かりました。
ありがとうございます。

ローカル変数はあまり使ってません。5,6個です
クラス変数に
・巨大な2次元配列
・大量の関数ポインタを保存したDictionary
があります。
関数が5万ぐらいあります。

引用返信 編集キー/
■85056 / inTopicNo.13)  Re[10]: C# MVC でのスタックオーバーフロー
□投稿者/ WebSurfer (1300回)-(2017/09/07(Thu) 18:09:54)
No85055 (はな さん) に返信

> C#のスタック領域変更が見つけられなかったので助かりました。
> ありがとうございます。

editbin は先のレスで紹介した記事に書いてあるのですが、見つからなかったようですね。


> ローカル変数はあまり使ってません。5,6個です
> クラス変数に
> ・巨大な2次元配列
> ・大量の関数ポインタを保存したDictionary
> があります。
> 関数が5万ぐらいあります。

そう言われても、何が問題で、どう改善するのがベストかは分かりません。少なくとも自分は。

ただ、スタックオーバーフローには間違いなさそうなので、解決策はスタックを増やすか、.dll を
書き換えてスタックの消費量を減らすかということになるはずです。

どういう手段を取るかは質問者さんが考えて決めることだと思います。(現状で、ここに書いてある
こと以外は何も知り得ない第三者が判断できることではなさそうです)
引用返信 編集キー/
■85057 / inTopicNo.14)  Re[10]: C# MVC でのスタックオーバーフロー
□投稿者/ 魔界の仮面弁士 (1405回)-(2017/09/07(Thu) 18:18:23)
2017/09/07(Thu) 18:19:09 編集(投稿者)

No85055 (はな さん) に返信
>> editbin /STACK:4000000 "C:\…\ConsoleApplication1.exe"
> C#のスタック領域変更が見つけられなかったので助かりました。

No85043 で紹介された URL にも書いてありましたよね?


ちなみに現在のスタックサイズを確認する場合は、
 DUMPBIN /headers ファイル
です。先の URL でも少し触れられていますが、
OPTIONAL HEADER VALUES という見出しの下に
  100000 size of stack reserve
 1000 size of stack commit
などと表示されるので、それで確認できます。

※DUMPBIN で commit も調整する場合は /STACK:reserve,commit



Web アプリの場合、IIS の実行プロセスを無理やり DUMPBIN で調整するというのも
リスクがありそうなので、再帰的な呼び出しが起きないよう、現状のコードを
組みなおすのが現実的なところかと思います。


あとは一応、こういうものもあるようですが…
使ったことが無いので、回避策になるかは分かりません。
https://msdn.microsoft.com/ja-jp/library/5cykbwz4.aspx
引用返信 編集キー/
■85095 / inTopicNo.15)  Re[11]: C# MVC でのスタックオーバーフロー
□投稿者/ はな (7回)-(2017/09/11(Mon) 12:45:09)
"C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\bin\editbin.exe" /STACK:1048576 C:\Windows\System32\inetsrv\w3wp.exe

LINK : fatal error LNK1104: ファイル 'w3wp.exe' を開くことができません。

引用返信 編集キー/
■85106 / inTopicNo.16)  Re[12]: C# MVC でのスタックオーバーフロー
□投稿者/ とっちゃん (459回)-(2017/09/11(Mon) 17:07:12)
No85095 (はな さん) に返信
> "C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\bin\editbin.exe" /STACK:1048576 C:\Windows\System32\inetsrv\w3wp.exe
>
> LINK : fatal error LNK1104: ファイル 'w3wp.exe' を開くことができません。
>

これだけだと何が言いたいのかよくわかりませんが、このエラー自体は、リンカーのエラーです。

おそらく、w3wp.exe のスタックサイズを広げれば解決するからやってみようとしたらエラーになった
ということなんだと思いますが、そもそも自分で開発しているアプリではないプログラムをむやみやたらと
書き換えていいということはありません。

特にシステムモジュールは、書き換えできないようにシステムレベルでロックダウンされるように作られているので
一時的に書き換えられたとしても、すぐに元に戻ってしまいます。


また、仮にスタックサイズを拡張できたとしても、変更されるのは開発環境だけで
運用環境が変わるわけではありません。
そのため、リリース後にスタックオーバーフローが発生して、エラーが再発することになります。

引用返信 編集キー/
■85111 / inTopicNo.17)  Re[13]: C# MVC でのスタックオーバーフロー
□投稿者/ はな (8回)-(2017/09/11(Mon) 21:14:08)
回答ありがとうございます。

IISExpressの方はこの方法でエラー回避できたので、これが一番楽だと思ったのですが、なかなか厳しいです。

この件に関して日本語の情報が少ないのも悩みです。

WFPやら、スレッドやらのやり取りがあるようなのですが、いまいち要領を得なくて・・・

もう少し試行錯誤してみます。
引用返信 編集キー/
■85112 / inTopicNo.18)  Re[14]: C# MVC でのスタックオーバーフロー
□投稿者/ Azulean (861回)-(2017/09/11(Mon) 21:37:54)
No85111 (はな さん) に返信
> もう少し試行錯誤してみます。

何を目指しているのでしょうか?
仮に、今スタックを増やすことができたとしても、そのようなスタックを浪費するコードを使い続ける限り、拡張・改良・修正も入るでしょうから、またスタックが足りなくなることが予想されます。
そして、いつかは限界を迎えます。


すでに指摘されているとおり、システムが提供する exe の改造は阻まれますし、Windows Update などで容易に置き換わりますので、考えに入れてはいけません。
スタックを浪費しないように修正することが将来性ある選択だとは思います。
(あるいは、プロセスを分けてしまい、別プロセスを走らせるという手もなくはないですが、別の悩みが出そうです)
引用返信 編集キー/
■85127 / inTopicNo.19)  Re[15]: C# MVC でのスタックオーバーフロー
□投稿者/ とっちゃん (460回)-(2017/09/12(Tue) 11:31:15)
No85111 (はな さん) に返信
> 回答ありがとうございます。
>
先に書いたのは回答ではありませんよ?


> IISExpressの方はこの方法でエラー回避できたので、これが一番楽だと思ったのですが、なかなか厳しいです。
>
先にも書いていますが、ご自身の開発環境でのみ解決できればいいのですか?

IISのプログラムのスタックサイズを拡張するのは回避策としては使えません。

システムファイルにはシステムが意図しない改変を自動的に修復するという仕組みが盛り込まれています。

ですので、一見成功したように見えてもすぐに戻ってしまうことになり何の意味もありません。



> もう少し試行錯誤してみます。

「スタック領域を拡張すれば解決するからスタック領域を拡張する」
という解決策は、スタック領域を自由に設定可能な自分で作成しているEXEの場合でのみ有効な解決策です。
IIS上で動くプログラムなど、ほかのプロセス内で動作するDLLの場合に用いることができる解決策ではありません。

なので、試行錯誤するのであれば、スタック消費量を減らす工夫か
再帰しないで動かす工夫を試行錯誤することをお勧めします。

引用返信 編集キー/
■85140 / inTopicNo.20)  Re[13]: C# MVC でのスタックオーバーフロー
 
□投稿者/ Jitta (309回)-(2017/09/12(Tue) 22:20:49)

・ヒープに移す
・再帰呼び出しではなく、データ構造で同じことをする
普通、検討するのはこのあたり。
引用返信 編集キー/

このトピックをツリーで一括表示

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

管理者用

- Child Tree -