StackOverflow エラーのデバッグ
StackOverflowException は、入れ子にされたメソッド呼び出しが多くなりすぎたために実行スタックがオーバーフローした場合にスローされます。 これは、メソッドが再帰的に 互いを呼び出しているために発生することがよくあります。
たとえば、次のようなアプリがあるとします。
using System;
namespace temp
{
class Program
{
static void Main(string[] args)
{
Main(args); // Oops, this recursion won't stop.
}
}
}
Main
メソッドは、スタック領域がなくなったまで、それ自体を継続的に呼び出します。 スタック領域がなくなると、実行を継続できず、StackOverflowException がスローされます。
> dotnet run
Stack overflow.
at temp.Program.Main(System.String[])
at temp.Program.Main(System.String[])
at temp.Program.Main(System.String[])
at temp.Program.Main(System.String[])
at temp.Program.Main(System.String[])
at temp.Program.Main(System.String[])
<this output repeats many more times>
このような出力でプログラムが終了する場合は、繰り返しメソッドのソース コードを見つけ、多数の呼び出しの原因となるロジックを調査できます。
デバッガーの使用
多くの場合、上記のコンソールでこの呼び出し履歴が表示されるだけで、問題のあるコードを識別するのに十分です。 ただし、問題がまだ不明な場合は、さらにデバッグできます。
この例では、StackOverflowException が発生したときにコア ダンプを作成し、そのダンプ lldb (一般的な Linux コマンド ライン デバッガー) に読み込んでデバッグします。
クラッシュ時にダンプを収集するように構成されたアプリを実行します。
> export DOTNET_DbgEnableMiniDump=1 > dotnet run Stack overflow. Writing minidump with heap to file /tmp/coredump.6412 Written 58191872 bytes (14207 pages) to core file
手記
.NET 6 では、.NET ランタイム動作を構成する環境変数の
COMPlus_
ではなく、プレフィックスDOTNET_
が標準化されています。 ただし、COMPlus_
プレフィックスは引き続き機能します。 以前のバージョンの .NET ランタイムを使用している場合でも、環境変数にはCOMPlus_
プレフィックスを使用する必要があります。dotnet-sos 使用して SOS 拡張機能をインストールします。
dotnet-sos install
lldb でダンプを開き、
bt
(backtrace) コマンドを使用してスタックを表示します。lldb --core /temp/coredump.6412 (lldb) bt ... frame #261930: 0x00007f59b40900cc frame #261931: 0x00007f59b40900cc frame #261932: 0x00007f59b40900cc frame #261933: 0x00007f59b40900cc frame #261934: 0x00007f59b40900cc frame #261935: 0x00007f5a2d4a080f libcoreclr.so`CallDescrWorkerInternal at unixasmmacrosamd64.inc:867 frame #261936: 0x00007f5a2d3cc4c3 libcoreclr.so`MethodDescCallSite::CallTargetWorker(unsigned long const*, unsigned long*, int) at callhelpers.cpp:70 frame #261937: 0x00007f5a2d3cc468 libcoreclr.so`MethodDescCallSite::CallTargetWorker(this=<unavailable>, pArguments=0x00007ffe8222e7b0, pReturnValue=0x0000000000000000, cbReturnValue=0) at callhelpers.cpp:604 frame #261938: 0x00007f5a2d4b6182 libcoreclr.so`RunMain(MethodDesc*, short, int*, PtrArray**) [inlined] MethodDescCallSite::Call(this=<unavailable>, pArguments=<unavailable>) at callhelpers.h:468 ...
上部フレーム
0x00007f59b40900cc
が複数回繰り返されます。 SOSip2md
コマンドを使用して、0x00007f59b40900cc
アドレスに配置されているマネージド メソッドを把握します。(lldb) ip2md 0x00007f59b40900cc MethodDesc: 00007f59b413ffa8 Method Name: temp.Program.Main(System.String[]) Class: 00007f59b4181d40 MethodTable: 00007f59b4190020 mdToken: 0000000006000001 Module: 00007f59b413dbf8 IsJitted: yes Current CodeAddr: 00007f59b40900a0 Version History: ILCodeVersion: 0000000000000000 ReJIT ID: 0 IL Addr: 0000000000000000 CodeAddr: 00007f59b40900a0 (MinOptJitted) NativeCodeVersion: 0000000000000000 Source file: /temp/Program.cs @ 9
指定されたメソッド temp.Program.Main(System.String[]) とソース "/temp/Program.cs @ 9" を確認して、コードの何が問題なのか把握できるかどうかを見てください。 追加情報が必要な場合は、さらにデバッガーを使用するか、SOS コマンドを実行してプロセスを検査できます。
.NET