[ 通常表示 ]  [ 簡易表示 ]  [ シンプル表示 ]

「分かりそう」で「分からない」でも「分かった」気になれるIT用語辞典イメージぴよ画像「分かりそう」で「分からない」でも「分かった」気になれるIT用語辞典

スタックトレース (stack trace)

pointこの用語のポイント

point処理の呼び出し履歴だよ

pointエラー発生までに、どの関数(メソッド)をどこで呼び出したかが表示されるよ

スポンサーリンク

簡単に書くよ

スタックトレース (stack trace)とは

エラーが発生したときに表示される内容で、そのエラーが発生するまでの過程(どんな処理がどの順番で呼び出されたかの流れ)を、ざっくりと表示したもの
です。

image piyo

詳しく書くよ

プログラミングのお話です。

プログラムを実行しました。
エラーが発生しました。
処理が中断しました。

そのときに表示される内容で、エラーが発生するまでに、どんな処理を、どの順番で呼び出したか表現したものが「スタックトレース」です。
メモリのスタック領域の内容が表示されているのでスタックトレースと言いますが、気にする必要はありません。

Javaを例に説明しましょう。

例えば、以下のようなJavaで書いたプログラムがあったとします。

public class test01 {
    public static void func01(){
        func02();
    }

    public static void func02(){
        func03();
    }

    public static void func03(){
        //Exception発生
        Integer a=10/0;
    }

    public static void main(String[] args){
        func01();
    }
}


分かりやすくするために、行番号を振っておきますね。

01public class test01 {
02    public static void func01(){
03        func02();
04    }
05
06    public static void func02(){
07        func03();
08    }
09
10    public static void func03(){
11        //Exception発生
12        Integer a=10/0;
13    }
14
15    public static void main(String[] args){
16        func01();
17    }
18}


このプログラムで最初に呼び出されるのは、15行目から始まる

15    public static void main(String[] args){
16        func01();
17    }


の部分です。
Javaのプログラムは(Java以外も大概はそうですが)「main」から処理が始まるのです。

さて、15行目から始まった処理ですが、16行目の

16        func01();

のところで「func01()」というメソッド関数みたいなもの)が呼び出されました。

そこで処理は、2行目から始まる

02    public static void func01(){
03        func02();
04    }


に移動します。

さらに、このタイミングで

1.main()の中にある16行目から飛びましたわ

という内容が、メモリのスタック領域という場所に書き込まれます。

スタックトレース

処理は進んで、次に3行目の

03        func02();

のところでメソッド「func02()」が呼び出されました。

そこで処理は、6行目から始まる

06    public static void func02(){
07        func03();
08    }


に移動します。

このタイミングで、先程と同じように

2.func01()の中にある3行目から飛びましたわ

という内容が、メモリのスタック領域という場所に書き込まれます。

スタックトレース2

注意点として、今回の内容は先程の内容に上積みされます。
つまり、実際には

2.func01()の中にある3行目から飛びましたわ
1.main()の中にある16行目から飛びましたわ


の形になります。
後から来たのが上に乗っかりますからね。

さらに処理は進んで、7行目の

07        func03();

のところでメソッド「func03」が呼ばれました。

そこで処理は、10行目から始まる

10    public static void func03(){
11        //Exception発生
12        Integer a=10/0;
13    }


に移動します。

このタイミングで、先程と同じように

3.func02()の中にある7行目から飛びましたわ

という内容が、メモリのスタック領域という場所に書き込まれます。

スタックトレース3

先程同様、実際には

3.func02()の中にある7行目から飛びましたわ
2.func01()の中にある3行目から飛びましたわ
1.main()の中にある16行目から飛びましたわ


の形になります。

さぁ、いよいよ佳境です。

12行目の処理

12        Integer a=10/0;

でエラーになります。

この処理は「10を0で割って、結果を『a』という箱に入れる」処理です。
0で割ることはできませんからね。
この12行目の処理が実行された時点で、エラーになります。

このタイミングで、メモリのスタック領域に

4.func03()の中にある12行目でエラーになりましたわ

という内容が、メモリのスタック領域という場所に書き込まれます。

スタックトレース4

先程同様、実際には

4.func03()の中にある12行目でエラーになりましたわ
3.func02()の中にある7行目から飛びましたわ
2.func01()の中にある3行目から飛びましたわ
1.main()の中にある16行目から飛びましたわ


の形になります。

そして、エラー発生時のスタック領域の内容、つまり

4.func03()の中にある12行目でエラーになりましたわ
3.func02()の中にある7行目から飛びましたわ
2.func01()の中にある3行目から飛びましたわ
1.main()の中にある16行目から飛びましたわ


を表示したのが、スタックトレースです。

スタックトレース5

実際のスタックトレースは、例えば以下のような内容です。

Exception in thread "main" java.lang.ArithmeticException: / by zero
        at test01.func03(test01.java:12)
        at test01.func02(test01.java:7)
        at test01.func01(test01.java:3)
        at test01.main(test01.java:16)


これにも行番号を振ってみましょう。

01Exception in thread "main" java.lang.ArithmeticException: / by zero
02        at test01.func03(test01.java:12)
03        at test01.func02(test01.java:7)
04        at test01.func01(test01.java:3)
05        at test01.main(test01.java:16)


まずは1行目の

01Exception in thread "main" java.lang.ArithmeticException: / by zero

に注目してください。
これは、要約すると

『java.lang.ArithmeticException: / by zero』ってエラーが発生したよ

と言っています。

次に2行目の

02        at test01.func03(test01.java:12)

を見てみましょう。
これは

func03()の中(「test01.java」の12行目)から飛んだよ(エラーになったよ)

という内容です。

同様に、3行目の

03        at test01.func02(test01.java:7)



func02()の中(「test01.java」の7行目)から飛んだよ

の意味ですし、4行目の

04        at test01.func01(test01.java:3)



func01()の中(「test01.java」の3行目)から飛んだよ

の意味ですし、5行目の

05        at test01.main(test01.java:16)



main()の中(「test01.java」の16行目)から飛んだよ

の意味です。

まとめると

『java.lang.ArithmeticException: / by zero』ってエラーが発生したよ
func03()の中(「test01.java」の12行目)から飛んだよ(エラーになったよ)
func02()の中(「test01.java」の7行目)から飛んだよ
func01()の中(「test01.java」の3行目)から飛んだよ
main()の中(「test01.java」の16行目)から飛んだよ


になります。

さらにもう一つ覚えておきましょう。

main()の中(「test01.java」の16行目)から飛んだよ

と書いてありますが、main()の中から一体どこに飛んだのでしょうね。

それは一つ上の

func01()の中(「test01.java」の3行目)から飛んだよ

を見れば分かります。

次は「func01()」からどこかへ飛んだのです。
ということは、そのひとつ前は「func01()」に飛んだことが分かります。

よって

func01()の中(「test01.java」の3行目)から飛んだよ
main()の中(「test01.java」の16行目)から飛んだよ


の2行を同時に見ることによって

main()の中(「test01.java」の16行目)から飛んだよ



main()の中(「test01.java」の16行目)から「func01()に」飛んだよ

と読み替えることができます。

同じ要領で、このスタックトレース全体を読み解くと

1.まず、main()が実行された
2.「test01.java」の16行目でmain()からfunc01()に移動した
3.「test01.java」の3行目でfunc01()からfunc02()に移動した
4.「test01.java」の7行目でfunc02()からfunc03()に移動した
5.「test01.java」の12行目でエラーになった
6.エラーの内容は「java.lang.ArithmeticException: / by zero」である


ということが分かります。
実際の処理の順番とスタックトレースの並び順が逆になっているので分かりにくいかもしれませんが、慣れればきっと読み解けるはずです。

この時点で「あれ?なんでこんな処理が動いているの?」となる場合もありますよね。
少なくとも、どのような順番でどのような処理(メソッド、関数)を呼び出したのかは把握することができます。

このように、スタックトレースは、エラー発生時の調査の助けとなる情報です。
パッと見では、ごちゃごちゃしていて読みにくく感じるかもしれませんが、頑張って解読できるようになってあげてください。

image piyo2

一言でまとめるよ

まぁ「スタックトレース」って単語が出てきたら「エラー発生時点までの処理の呼び出し履歴なんだな~」と、お考えください。

一番上に戻るよ
スポンサーリンク