programing

스택 트레이스란 무엇입니까?어플리케이션오류를 디버깅하려면 어떻게 해야 하나요?

prostudy 2022. 8. 3. 20:50
반응형

스택 트레이스란 무엇입니까?어플리케이션오류를 디버깅하려면 어떻게 해야 하나요?

응용 프로그램을 실행하면 다음과 같은 오류가 발생할 수 있습니다.

Exception in thread "main" java.lang.NullPointerException
        at com.example.myproject.Book.getTitle(Book.java:16)
        at com.example.myproject.Author.getBookTitles(Author.java:25)
        at com.example.myproject.Bootstrap.main(Bootstrap.java:14)

이것을 「스택 트레이스」라고 부릅니다.스택 트레이스란?프로그램에서 발생한 오류에 대해 무엇을 알 수 있습니까?


이 질문에 대해서 - 초보 프로그래머가 "오류 발생"하는 질문을 자주 볼 수 있는데, 스택 트레이스가 무엇인지, 어떻게 사용할 수 있는지 이해하지 못한 채 스택 트레이스와 코드 랜덤 블록을 붙여넣기만 하면 됩니다.이 질문은 스택 트레이스의 가치를 이해하는 데 도움이 필요할 수 있는 초보 프로그래머를 위한 참고 자료입니다.

간단히 말하면 스택트레이스는 예외가 발생했을 때 응용 프로그램이 중간에 있었던 메서드콜의 목록입니다

간단한 예

질문의 예를 통해 어플리케이션에서 예외가 발생한 위치를 정확하게 파악할 수 있습니다.다음으로 스택 트레이스를 살펴보겠습니다.

Exception in thread "main" java.lang.NullPointerException
        at com.example.myproject.Book.getTitle(Book.java:16)
        at com.example.myproject.Author.getBookTitles(Author.java:25)
        at com.example.myproject.Bootstrap.main(Bootstrap.java:14)

이것은 매우 단순한 스택트레이스입니다"at..." 목록의 선두에서 시작하면 오류가 발생한 위치를 알 수 있습니다.델이 찾고 있는 것은 어플리케이션의 일부인 최상위 메서드 호출입니다.이 경우, 다음과 같습니다.

at com.example.myproject.Book.getTitle(Book.java:16)

, 「 」를 엽니다.Book.java,그러면줄보세요.16 '먹다', '먹다', '먹다'입니다

15   public String getTitle() {
16      System.out.println(title.toString());
17      return title;
18   }

은, 아마도 「」라고 하는 것)를 .title는 )개요null을 사용하다

예외 연쇄가 있는 예제

경우에 따라서는, 애플리케이션이 예외를 검출해, 그것을 다른 예외의 원인으로 재투입합니다.이것은 일반적으로 다음과 같습니다.

34   public void getBookIds(int id) {
35      try {
36         book.getId(id);    // this method it throws a NullPointerException on line 22
37      } catch (NullPointerException e) {
38         throw new IllegalStateException("A book has a null property", e)
39      }
40   }

이렇게 하면 다음과 같은 스택트레이스를 얻을 수 있습니다

Exception in thread "main" java.lang.IllegalStateException: A book has a null property
        at com.example.myproject.Author.getBookIds(Author.java:38)
        at com.example.myproject.Bootstrap.main(Bootstrap.java:14)
Caused by: java.lang.NullPointerException
        at com.example.myproject.Book.getId(Book.java:22)
        at com.example.myproject.Author.getBookIds(Author.java:36)
        ... 1 more

다른 점은 "Caused by"입니다.예외에는 여러 개의 "원인" 섹션이 있을 수 있습니다.이러한 경우 일반적으로 스택트레이스에서 가장 낮은 "원인" 섹션 중 하나가 되는 "근본 원인"을 찾습니다.이 경우 다음과 같습니다.

Caused by: java.lang.NullPointerException <-- root cause
        at com.example.myproject.Book.getId(Book.java:22) <-- important line

한 번 , 이는 제외하고, 우리는, ᄃ자, ᄃ자, ᄃ자, ᄃ자, ᄃ자, ᄃ자, ᄃ자, ᄂ자, ᄂ자, ᄂ자, ᄂ자, ᄂ자, ᄂ자, ᄃ자, 22Book.java무엇이 이 될 수 를 조사하다NullPointerException

라이브러리 코드에 관한 보다 위압적인 예

일반적으로 스택 트레이스는 위의 두 가지 예보다 훨씬 복잡합니다.다음은 예를 제시하겠습니다(긴 예이지만 여러 수준의 연쇄 예외를 보여줍니다).

javax.servlet.ServletException: Something bad happened
    at com.example.myproject.OpenSessionInViewFilter.doFilter(OpenSessionInViewFilter.java:60)
    at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157)
    at com.example.myproject.ExceptionHandlerFilter.doFilter(ExceptionHandlerFilter.java:28)
    at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157)
    at com.example.myproject.OutputBufferFilter.doFilter(OutputBufferFilter.java:33)
    at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157)
    at org.mortbay.jetty.servlet.ServletHandler.handle(ServletHandler.java:388)
    at org.mortbay.jetty.security.SecurityHandler.handle(SecurityHandler.java:216)
    at org.mortbay.jetty.servlet.SessionHandler.handle(SessionHandler.java:182)
    at org.mortbay.jetty.handler.ContextHandler.handle(ContextHandler.java:765)
    at org.mortbay.jetty.webapp.WebAppContext.handle(WebAppContext.java:418)
    at org.mortbay.jetty.handler.HandlerWrapper.handle(HandlerWrapper.java:152)
    at org.mortbay.jetty.Server.handle(Server.java:326)
    at org.mortbay.jetty.HttpConnection.handleRequest(HttpConnection.java:542)
    at org.mortbay.jetty.HttpConnection$RequestHandler.content(HttpConnection.java:943)
    at org.mortbay.jetty.HttpParser.parseNext(HttpParser.java:756)
    at org.mortbay.jetty.HttpParser.parseAvailable(HttpParser.java:218)
    at org.mortbay.jetty.HttpConnection.handle(HttpConnection.java:404)
    at org.mortbay.jetty.bio.SocketConnector$Connection.run(SocketConnector.java:228)
    at org.mortbay.thread.QueuedThreadPool$PoolThread.run(QueuedThreadPool.java:582)
Caused by: com.example.myproject.MyProjectServletException
    at com.example.myproject.MyServlet.doPost(MyServlet.java:169)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:727)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:820)
    at org.mortbay.jetty.servlet.ServletHolder.handle(ServletHolder.java:511)
    at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1166)
    at com.example.myproject.OpenSessionInViewFilter.doFilter(OpenSessionInViewFilter.java:30)
    ... 27 more
Caused by: org.hibernate.exception.ConstraintViolationException: could not insert: [com.example.myproject.MyEntity]
    at org.hibernate.exception.SQLStateConverter.convert(SQLStateConverter.java:96)
    at org.hibernate.exception.JDBCExceptionHelper.convert(JDBCExceptionHelper.java:66)
    at org.hibernate.id.insert.AbstractSelectingDelegate.performInsert(AbstractSelectingDelegate.java:64)
    at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:2329)
    at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:2822)
    at org.hibernate.action.EntityIdentityInsertAction.execute(EntityIdentityInsertAction.java:71)
    at org.hibernate.engine.ActionQueue.execute(ActionQueue.java:268)
    at org.hibernate.event.def.AbstractSaveEventListener.performSaveOrReplicate(AbstractSaveEventListener.java:321)
    at org.hibernate.event.def.AbstractSaveEventListener.performSave(AbstractSaveEventListener.java:204)
    at org.hibernate.event.def.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:130)
    at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.saveWithGeneratedOrRequestedId(DefaultSaveOrUpdateEventListener.java:210)
    at org.hibernate.event.def.DefaultSaveEventListener.saveWithGeneratedOrRequestedId(DefaultSaveEventListener.java:56)
    at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.entityIsTransient(DefaultSaveOrUpdateEventListener.java:195)
    at org.hibernate.event.def.DefaultSaveEventListener.performSaveOrUpdate(DefaultSaveEventListener.java:50)
    at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.onSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:93)
    at org.hibernate.impl.SessionImpl.fireSave(SessionImpl.java:705)
    at org.hibernate.impl.SessionImpl.save(SessionImpl.java:693)
    at org.hibernate.impl.SessionImpl.save(SessionImpl.java:689)
    at sun.reflect.GeneratedMethodAccessor5.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    at java.lang.reflect.Method.invoke(Method.java:597)
    at org.hibernate.context.ThreadLocalSessionContext$TransactionProtectionWrapper.invoke(ThreadLocalSessionContext.java:344)
    at $Proxy19.save(Unknown Source)
    at com.example.myproject.MyEntityService.save(MyEntityService.java:59) <-- relevant call (see notes below)
    at com.example.myproject.MyServlet.doPost(MyServlet.java:164)
    ... 32 more
Caused by: java.sql.SQLException: Violation of unique constraint MY_ENTITY_UK_1: duplicate value(s) for column(s) MY_COLUMN in statement [...]
    at org.hsqldb.jdbc.Util.throwError(Unknown Source)
    at org.hsqldb.jdbc.jdbcPreparedStatement.executeUpdate(Unknown Source)
    at com.mchange.v2.c3p0.impl.NewProxyPreparedStatement.executeUpdate(NewProxyPreparedStatement.java:105)
    at org.hibernate.id.insert.AbstractSelectingDelegate.performInsert(AbstractSelectingDelegate.java:57)
    ... 54 more

이 예에서는 더 많은 것이 있습니다.우리가 가장 염려하는 것은 우리의 코드에서 나온 방법을 찾는 것이다.com.example.myproject 두 번째에서는 먼저 즉 '어느 정도으)로 하다', '어느 정도(으)로 하다'를 내려보려고

Caused by: java.sql.SQLException

단, 그 아래에 있는 메서드콜은 모두 라이브러리 코드입니다. 위에 있는 '원인'으로 넘어가서 그 '원인' 블록에서 코드에서 발신된 첫 번째 메서드콜을 찾습니다

at com.example.myproject.MyEntityService.save(MyEntityService.java:59)

예시와 '아까보다'를 합니다.MyEntityService.java이요.59이 에러가 발생한 것은, 이 에러의 발생원이기 때문입니다(SQLException에 에러가 기재되어 있기 때문에, 이 에러의 원인은 조금 명확합니다만, 디버깅 순서는 이 에러의 발생원인이 됩니다).

스택 트레이스란?

스택 트레이스는 매우 유용한 디버깅툴입니다수집되지 않은 예외가 발생한 시각(또는 스택트레이스가 수동으로 생성된 시각)의 콜스택(즉, 그 시점까지 호출된 함수의 스택)이 표시됩니다.이는 오류가 발생한 위치뿐만 아니라 프로그램이 어떻게 코드의 해당 위치에 있는지 보여 주기 때문에 매우 유용합니다.그러면 다음 질문으로 이어집니다.

예외란?

예외는 런타임 환경에서 오류가 발생했음을 알리기 위해 사용하는 것입니다.일반적인 예로는 Null Pointer가 있습니다.예외: IndexOutOfBoundsException 또는 MalcetricException.이 모든 것은 불가능한 일을 하려고 할 때 발생합니다.예를 들어 Null Pointer는Null 개체를 참조 해제하려고 하면 예외가 발생합니다.

Object a = null;
a.toString();                 //this line throws a NullPointerException

Object[] b = new Object[5];
System.out.println(b[10]);    //this line throws an IndexOutOfBoundsException,
                              //because b is only 5 elements long
int ia = 5;
int ib = 0;
ia = ia/ib;                   //this line throws an  ArithmeticException with the 
                              //message "/ by 0", because you are trying to
                              //divide by 0, which is not possible.

스택 트레이스/예외에 어떻게 대처해야 합니까?

먼저 예외의 원인을 파악합니다.예외의 원인을 검색하여 해당 예외의 이름을 검색해 보십시오.대부분의 경우 잘못된 코드로 인해 발생합니다.위의 예에서는 모든 예외가 잘못된 코드로 인해 발생합니다.따라서 Null Null Pointer의 에서는 "예외"가 "예외"로 설정되어 할 수 .a그 시점에서는 무효가 되지 않습니다. ''를 할 수 .a또는 다음과 같은 체크 표시를 포함합니다.

if (a!=null) {
    a.toString();
}

하면 .a==null하다

때때로 당신은 당신이 예외를 받지 않도록 확실히 할 수 없다.예를 들어 프로그램에서 네트워크 연결을 사용하는 경우 컴퓨터의 인터넷 연결이 끊어지는 것을 중지할 수 없습니다(예: 사용자가 컴퓨터의 네트워크 연결을 끊는 것을 중지할 수 없습니다).이 경우 네트워크 라이브러리에서 예외가 발생할 수 있습니다.이제 당신은 예외를 포착하고 처리해야 합니다.즉, 네트워크 접속의 예에서는 접속을 다시 열거나 사용자에게 통지하거나 해야 합니다.또한 catch를 사용할 때는 항상 잡고 싶은 예외만 잡고, 모든 예외를 잡을 수 있는 광범위한 catch 문장은 사용하지 마십시오.이는 매우 중요합니다. 그렇지 않으면 실수로 잘못된 예외를 발견하고 잘못된 방식으로 반응할 수 있기 때문입니다.

try {
    Socket x = new Socket("1.1.1.1", 6789);
    x.getInputStream().read()
} catch (IOException e) {
    System.err.println("Connection could not be established, please try again later!")
}

왜 사용하지 않는가 무엇입니까?catch (Exception e)

작은 예를 들어 모든 예외만 포착해서는 안 되는 이유를 설명하겠습니다.

int mult(Integer a,Integer b) {
    try {
        int result = a/b
        return result;
    } catch (Exception e) {
        System.err.println("Error: Division by zero!");
        return 0;
    }
}

것은, 「」를 입니다.ArithmeticException0.하기 때문에 합니다.하지만 또 다른 가능성을 포착하기도 합니다.NullPointerException 던지다a ★★★★★★★★★★★★★★★★★」bnull '나', '나', '나', '나', '나', '나',NullPointerException하지만 산술적 예외로 취급하고 잘못된 행동을 할 수도 있습니다.로는 Null 알 수 없습니다. .디버깅이 더 어려워지니까 하지 마세요.

TLDR

  1. 예외의 원인을 파악하여 예외가 전혀 발생하지 않도록 수정합니다.
  2. 1 특정 한다.1이 불가능한 경우 특정 예외를 포착하여 처리한다.
    • try/catch만 추가한 후 예외를 무시하지 마십시오.그렇게 하지 마.
    • 사용하지 .catch (Exception e) , 항상특특 , , , 。그것은 당신의 두통을 많이 덜어줄 것입니다.

Rob이 말한 것에 더하다.응용 프로그램에서 중단점을 설정하면 스택을 단계별로 처리할 수 있습니다.이를 통해 개발자는 디버거를 사용하여 메서드가 예기치 않은 작업을 수행하는 정확한 지점을 확인할 수 있습니다.

이 Rob을 NullPointerException의 일반적인 , (NPE)의 경우는, 이 할 수

매개 가 있는 :void (String firstName)

에서는, 그 코드에 대해 하고 있습니다.firstName, 할 수 있습니다.이렇게 하겠습니다.if(firstName == null || firstName.equals("")) return;

의 내용 는 위위사 the the the the the the the the the the the the the the the the the the the the the the the the the the the the를 사용할 수 없습니다.firstName안전하지 않은 매개 변수입니다.따라서 처리 전에 null 체크를 실시함으로써 코드가 올바르게 동작하는지 확인할 수 있습니다.한 예를 , 「」를 .

if(dog == null || dog.firstName == null) return;

위의 순서는 null을 확인하는 적절한 순서입니다.기본 객체(이 경우 dog)부터 시작하여 처리 전에 모든 것이 유효한지 확인하기 위해 가능한 트리를 걷기 시작합니다.순서가 뒤바뀌면 NPE가 투척되어 프로그램이 크래쉬 할 가능성이 있습니다.

이름을 이해하려면:스택 트레이스는 가장 표면적인 예외(서비스 계층 예외 등)에서 가장 깊은 예외(데이터베이스 예외 등)까지의 예외 목록입니다.스택이라고 하는 이유는 스택이 First in Last Out(FILO)이기 때문입니다.처음에는 가장 깊은 예외가 발생했고, 그 후 일련의 예외의 연쇄가 생성되었습니다.예외 표면은 제시간에 발생한 마지막 예외입니다만, 애당초 확인되었습니다.

요점 1: 여기서 이해해야 할 까다롭고 중요한 것은 가장 깊은 원인이 '근본적인 원인'이 아닐 수 있다는 것입니다.왜냐하면 '불량 코드'를 쓰면 그 아래에 레이어보다 더 깊은 예외가 발생할 수 있기 때문입니다.예를 들어 sql 쿼리가 잘못되면 스택 중간에 있는 syndax 오류 대신 SQL Server Exception 연결이 bottem에서 리셋될 수 있습니다.

-> 일의 중간에서 근본 원인을 찾아냅니다.여기에 이미지 설명 입력

2: 까다롭지만 중요한 또 다른 점은 각 "원인별" 블록 안에 있습니다. 첫 번째 줄은 가장 깊은 레이어이며 이 블록의 첫 번째 위치가 됩니다.예를 들어.

Exception in thread "main" java.lang.NullPointerException
        at com.example.myproject.Book.getTitle(Book.java:16)
           at com.example.myproject.Author.getBookTitles(Author.java:25)
               at com.example.myproject.Bootstrap.main(Bootstrap.java:14)

Book.java:16이 Auther.java:25에 의해 호출되었으며 Bootstrap.java:14에 의해 호출되었으며 Book.java:16이 근본 원인입니다.여기에 트레이스 스택을 시간순으로 정렬하는 다이어그램을 첨부합니다.여기에 이미지 설명 입력

스택 트레이스 기능에는 스택트레이스 정보를 조작할 수 있는 기능이 1개 더 있습니다.

표준 동작:

package test.stack.trace;

public class SomeClass {

    public void methodA() {
        methodB();
    }

    public void methodB() {
        methodC();
    }

    public void methodC() {
        throw new RuntimeException();
    }

    public static void main(String[] args) {
        new SomeClass().methodA();
    }
}

스택 트레이스:

Exception in thread "main" java.lang.RuntimeException
    at test.stack.trace.SomeClass.methodC(SomeClass.java:18)
    at test.stack.trace.SomeClass.methodB(SomeClass.java:13)
    at test.stack.trace.SomeClass.methodA(SomeClass.java:9)
    at test.stack.trace.SomeClass.main(SomeClass.java:27)

조작된 스택 트레이스:

package test.stack.trace;

public class SomeClass {

    ...

    public void methodC() {
        RuntimeException e = new RuntimeException();
        e.setStackTrace(new StackTraceElement[]{
                new StackTraceElement("OtherClass", "methodX", "String.java", 99),
                new StackTraceElement("OtherClass", "methodY", "String.java", 55)
        });
        throw e;
    }

    public static void main(String[] args) {
        new SomeClass().methodA();
    }
}

스택 트레이스:

Exception in thread "main" java.lang.RuntimeException
    at OtherClass.methodX(String.java:99)
    at OtherClass.methodY(String.java:55)

다른 예시에 덧붙이자면, 내부(내포) 클래스가 있습니다.$ sign. §:

public class Test {

    private static void privateMethod() {
        throw new RuntimeException();
    }

    public static void main(String[] args) throws Exception {
        Runnable runnable = new Runnable() {
            @Override public void run() {
                privateMethod();
            }
        };
        runnable.run();
    }
}

다음과 같은 스택트레이스가 발생합니다.

Exception in thread "main" java.lang.RuntimeException
        at Test.privateMethod(Test.java:4)
        at Test.access$000(Test.java:1)
        at Test$1.run(Test.java:10)
        at Test.main(Test.java:13)

다른 투고에서는 스택트레이스란 무엇인지 설명하고 있습니다만, 조작이 어려운 경우가 있습니다.

스택 트레이스를 취득하여 예외의 원인을 추적하려면 Eclipse에서 Java Stack Trace Console을 사용하는 것이 좋습니다.다른 IDE를 사용하는 경우에도 유사한 기능이 있을 수 있지만 이 답변은 Eclipse에 대한 것입니다.

먼저 Eclipse 프로젝트에서 모든 Java 원본에 액세스할 수 있는지 확인하십시오.

그런 다음 Java 관점에서 Console 탭(보통 맨 아래)을 클릭합니다.[ Console ]뷰가 표시되지 않으면 메뉴 옵션인 [Window]-> [ Show View ]으로 이동하여 [Console]를 선택합니다.

그런 다음 콘솔 창에서 다음 버튼(오른쪽)을 클릭합니다.

[ Consoles ]단추

드롭다운 목록에서 [Java Stack Trace Console]를 선택합니다.

스택 트레이스를 콘솔에 붙여넣습니다.그런 다음 소스 코드에 대한 링크 목록과 사용 가능한 다른 소스 코드를 제공합니다.

다음과 같이 표시됩니다(Eclipse 문서의 이미지).

Eclipse 문서의 다이어그램

가장 최근에 발신된 메서드콜은 스택의 맨 (메시지 텍스트 제외)가 됩니다.스택 다운은 과거로 거슬러 올라간다.두 번째 회선은 첫 번째 회선 등을 호출하는 방식입니다.

오픈 소스 소프트웨어를 사용하는 경우 검토하려는 원본을 다운로드하여 프로젝트에 첨부해야 할 수 있습니다.소스 jar를 다운로드하여 프로젝트에서 Referenced Libraries 폴더를 열고 오픈 소스 모듈용 jar(클래스 파일이 있는 jar)를 찾은 후 마우스 오른쪽 버튼을 클릭하여 Properties를 선택하고 소스 jar를 첨부합니다.

언급URL : https://stackoverflow.com/questions/3988788/what-is-a-stack-trace-and-how-can-i-use-it-to-debug-my-application-errors

반응형