Java에서 예외를 발생시키지 않고 스택 추적을 덤프하는 방법이 있습니까?


159

Java 응용 프로그램을위한 디버그 도구를 만들려고합니다.

Exception.printStackTrace()실제로 예외를 throw하지 않고 스택 추적을 얻을 수 있는지 궁금합니다 .

내 목표는 주어진 메소드에서 스택을 덤프하여 메소드 호출자가 누구인지 확인하는 것입니다.

답변:


84

또한 Thread.getAllStackTraces()살아있는 모든 스레드에 대한 스택 추적 맵을 얻으 려고 시도 할 수 있습니다 .


250

예, 간단히 사용하십시오

Thread.dumpStack()

44
...하지만 던지지는 않습니다.
Rob

5
이것이 실제로 문제를 해결하는 답입니다.
bruno

7
매우 간단하고 우아합니다. 이것은 받아 들여진 대답이어야합니다.
deLock

11
이 방법의 근원 인 public static void dumpStack() { new Exception("Stack trace").printStackTrace(); }
Fwiw

에 출력하는 것에 만족한다면 이것은 질문에 대한 가장 좋은 대답 stderr입니다.
마이크 설치류

46

Ram의 제안과 같이 시스템의 모든 스레드가 아닌 현재 스레드에 대한 추적을 원한다면 다음을 수행하십시오.

Thread.currentThread (). getStackTrace ()

발신자를 찾으려면 다음을 수행하십시오.

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

그리고 호출자가 누구인지 알아야하는 메소드 내에서 해당 메소드를 호출하십시오. 그러나 경고 단어 : 목록 내 호출 프레임의 색인은 JVM에 따라 다를 수 있습니다! 추적이 생성되는 지점에 도달하기 전에 getStackTrace 내에있는 호출 계층 수에 따라 다릅니다. 보다 강력한 솔루션은 추적을 가져 와서 getCallingMethodName에 대한 프레임을 찾은 후 반복하여 진정한 호출자를 찾기위한 것입니다.


2
따라서 새로운 예외를 직접 만들고 [1]을 색인으로 사용하십시오!
Daniel

3
이 질문의 제목은 "예외를 던지지 않고"라고 말합니다. 물론 예외를 만들 것을 제안하지만 그것을 던지지 말 것을 제안하지만 여전히 질문의 정신에 있지 않다고 생각합니다.
톰 앤더슨

1
당연하지. 예외를 만드는 것이 스택 트레이스를 얻는 가장 낮은 수준의 방법입니다. 심지어 Thread.currentThread (). getStackTrace ()조차도 그렇게하지만 내 길은 더 빠릅니다 :).
Daniel

@Daniel 또 다른 고려 사항이 있습니다 : Spock과 같은 많은 테스트 프레임 워크를 사용하면 예외를 throw하지 않고 예외를 생성하는 것만으로 충분합니다. 테스트는 예외가 "발생"한 것으로 간주하고 테스트는 실패로 끝납니다.
mike rodent

@ mikerodent : 확실합니까? Spock은 에이전트를 사용해야합니다. 그러나 어쨌든 클래스를 호출해야하기 때문에 유틸리티 함수에 Reflection.getCallerClass (2)를 사용했습니다. 그런 식으로 함수와 줄 번호를 얻지 못할 것이라고 생각했습니다.
Daniel

37

다음과 같은 스택 추적을 얻을 수 있습니다.

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

프레임에 액세스하려면 t.getStackTrace ()를 사용하여 스택 프레임의 배열을 얻을 수 있습니다.

핫스팟 컴파일러가 작업 최적화에 바쁘면이 스택 추적 (다른 것과 마찬가지로)에 일부 프레임이 누락 될 수 있습니다.


나는 출력을 지시 할 수있는 기회를 제공하기 때문에이 대답을 좋아합니다. 나는 대체 할 수 t.printStackTrace와 함께 t.printStackTrace(System.out).

4
한 줄로 :new Throwable().printStackTrace(System.out);

1
이것이 정답입니다. 간단하고 간단합니다! 공유해 주셔서 감사합니다
Sam

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

6

프로세스에 QUIT 신호를 보내 실행중인 Java 프로세스에서 Thread.getAllStackTraces ()를 실행하도록 신호를 JVM에 보낼 수도 있습니다.

유닉스 / 리눅스에서 :

kill -QUIT process_id여기서 process_id는 Java 프로그램의 프로세스 번호입니다.

Windows에서는 콘솔 프로세스를 실행하지 않으면 일반적으로 표시되지 않지만 응용 프로그램에서 Ctrl-Break를 누를 수 있습니다.

JDK6에는 컴퓨터에서 실행중인 JDK6 프로세스의 스택을 표시하는 또 다른 옵션 인 jstack 명령이 도입되었습니다.

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

자바 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 HPROF를 프로세스에 연결하고 언제든지 Control- \를 눌러 힙 덤프, 실행중인 스레드 등을 출력 할 수 있습니다. . . 응용 프로그램 코드를 정리하지 않고. 이것은 약간 구식이지만 Java 6에는 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.