Javaで例外をスローせずにスタックトレースをダンプする方法はありますか?


159

Javaアプリケーション用のデバッグツールを作成することを考えています。

のようにスタックトレースを取得することは可能ですか? Exception.printStackTrace()ですか?

私の目標は、特定のメソッドでスタックをダンプして、メソッドの呼び出し元が誰であるかを確認することです。

回答:


84

またThread.getAllStackTraces()、有効なすべてのスレッドのスタックトレースのマップを取得することもできます。


250

はい、単に使用します

Thread.dumpStack()

44
...しかしそれを投げません。
Rob

5
それが実際に質問に答える答えです。
ブルーノ2015年

7
とてもシンプルでエレガント。これは受け入れられるべき答えでした。
deLock

11
Fwiw、このメソッドのソース: public static void dumpStack() { new Exception("Stack trace").printStackTrace(); }
JohnK

これは、への出力に満足している場合の質問に対する最良の回答です。これは、質問stderrの意味合いのようです。
マイクげっ歯類

46

(Ramの提案のようにシステム内のすべてのスレッドではなく)現在のスレッドのみのトレースが必要な場合は、次のようにします。

Thread.currentThread()。getStackTrace()

発信者を見つけるには、次のようにします。

private String getCallingMethodName() {
    StackTraceElement callingFrame = Thread.currentThread().getStackTrace()[4];
    return callingFrame.getMethodName();
}

そして、その呼び出し元が誰であるかを知る必要があるメソッド内からそのメソッドを呼び出します。ただし、警告の言葉:リスト内の呼び出しフレームのインデックスは、JVMによって異なる可能性があります!すべては、トレースが生成されるポイントに到達する前に、getStackTrace内にある呼び出しのレイヤーの数に依存します。より堅牢なソリューションは、トレースを取得し、それを反復してgetCallingMethodNameのフレームを探し、さらに2つの手順を実行して真の呼び出し元を見つけることです。


2
自分で新しい例外を作成し、[1]をインデックスとして使用してください。
ダニエル

3
この質問のタイトルには、「例外をスローせずに」と書かれています。確かに、例外を作成するがスローしないことをお勧めしますが、それでも問題の精神ではないと思います。
トムアンダーソン

1
もちろん。例外の作成は、スタックトレースを取得するための最も低レベルの方法です。あなたのThread.currentThread()。getStackTrace()もそれを行いますが、私の方法はそれをより速くします:)。
ダニエル

@Daniel別の考慮事項があります。たとえば、Spockなどの多くのテストフレームワークでは、例外を(スローせずに)作成するだけで、フレームワークがピックアップできます。テストは、例外が「発生した」と見なし、テストは最後に、失敗しました。
マイクげっ歯類

@mikerodent:よろしいですか?Spockはそのためにエージェントを使用する必要があります。しかし、とにかく、クラスを呼び出す必要があるだけなので、ユーティリティ関数でReflection.getCallerClass(2)を使用しました。関数と行番号をそのように取得することはできないと思いました。
ダニエル

37

次のようなスタックトレースを取得できます。

Throwable t = new Throwable();
t.printStackTrace();

フレームにアクセスする場合は、t.getStackTrace()を使用してスタックフレームの配列を取得できます。

ホットスポットコンパイラが最適化のためにビジー状態である場合、このスタックトレース(他のスタックトレースと同様)で一部のフレームが失われる可能性があることに注意してください。


この回答は、出力を指示する機会を提供してくれるので、気に入っています。私は置き換えることができt.printStackTracet.printStackTrace(System.out)

4
1行で:new Throwable().printStackTrace(System.out);

1
これは受け入れられる答えになるはずです。シンプルでわかりやすい!共有してくれてありがとう
サム

2
java.util.Loggerに送信するのは簡単ですlog.log(Level.SEVERE, "Failed to do something", new Throwable());
MitchBroadhead

13

Thread.dumpStack()が実際に例外をスローすることに注意してください。

new Exception("Stack trace").printStackTrace();

12
例外が発生しますが、スローされません。
MatrixFrog 2014

6

プロセスにQUITシグナルを送信することにより、実行中のJavaプロセスでThread.getAllStackTraces()を実行するためにシグナルをJVMに送信することもできます。

Unix / Linuxの場合:

kill -QUIT process_idここで、process_idはJavaプログラムのプロセス番号です。

Windowsでは、アプリケーションでCtrl-Breakを押すことができますが、通常、コンソールプロセスを実行している場合を除き、これは表示されません。

JDK6には、別のオプションであるjstackコマンドが導入されました。これは、コンピューターで実行中のJDK6プロセスのスタックを表示します。

jstack [-l] <pid>

これらのオプションは、運用環境で実行されていて簡単に変更できないアプリケーションに非常に役立ちます。ランタイムデッドロックやパフォーマンスの問題を診断するのに特に役立ちます。

http://java.sun.com/developer/technicalArticles/Programming/Stacktrace/ http://java.sun.com/javase/6/docs/technotes/tools/share/jstack.html


6

キャプチャ出力が必要な場合

StringWriter sw = new StringWriter();
new Throwable("").printStackTrace(new PrintWriter(sw));
String stackTrace = sw.toString();

6

Java 9は StackWalker、スタックをウォークするためおよびサポートするクラスが。

以下は、Javadocからの抜粋です。

このwalkメソッドStackFramesは、現在のスレッドの順次ストリームを開き、指定された関数を適用してStackFrameストリームをウォークします。ストリームは、スタックが生成された実行ポイントを表す最上部のフレームから最下部のフレームまで、スタックフレーム要素を順番に報告します。StackFrameストリームは時に歩行メソッドが返す閉じられています。閉じたストリームを再利用しようとすると、IllegalStateExceptionがスローされます。

...

  1. 現在のスレッドのトップ10スタックフレームをスナップショットするには、

    List<StackFrame> stack = StackWalker.getInstance().walk(s ->
     s.limit(10).collect(Collectors.toList()));

0

HPROF Javaプロファイラー

コードでこれを行う必要さえありません。Java HPROFをプロセスに接続し、いつでもControl- \を押して、ヒープダンプや実行中のスレッドなどを出力できます。。。アプリケーションコードを変更する必要はありません。これは少し時代遅れです。Java6にはGUI jconsoleが付属していますが、HPROFは非常に便利だと思います。


0

Rob Di Marco回答は、に出力してよかった場合に断然最良ですstderr

String通常のトレースに従って新しい行を使用してにキャプチャする場合は、次のようにします。

Arrays.toString(Thread.currentThread().getStackTrace()).replace( ',', '\n' );
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.