glenn-syj / more-effective-java

이펙티브 자바를 읽으며 자바를 더 효율적으로 공부합니다
4 stars 5 forks source link

[MEJ-013] 예외 처리에 자원이 소모되는 이유 #218

Open undeadtimo opened 1 month ago

undeadtimo commented 1 month ago

based on: #216 by @FickleBoBo


바쁜 와중에도 고찰과 경험이 담긴 글을 작성해주셔서 흥미롭게 읽었습니다.

Exception을 통한 예외 처리에 대하여 자원이 소모될 것이라고는 생각지도 못했으나, 예외 처리에 따른 여러 기능이 존재하기 때문에 이 부분에 대해 생각해본다면 당연하게 도달할 수 있는 결론인 것 같습니다.

그러나 예외를 던지는 것보다는 빈 배열을 반환하도록 하는 것이 좋다는 것만을 인식했을 뿐, 어째서 그러한 결과가 나오는 지에 대해 무지하기 때문에 다음 사항에 대해 조사해보고자 합니다.

예외 처리를 할 때 정확히 어떤 부분들에서 자원이 소모될 수 있으며, 그러한 자원 소모를 줄이기 위해서는 어떻게 해야하는가.


Java에서 예외를 처리할 때 특히 자원의 소모가 큰 이유는 stack trace 관련 메서드 때문이라고 합니다.

Java에서 예외가 발생하면 fillInStackTrace()라는 메서드가 자동으로 호출됩니다.

fillInStackTrace는 함수의 호출 스택을 역추적하면서 기록하는 메서드입니다.

간단하게 예시를 들자면

public String method1(){
    public String method2(){
        // 예외를 발생시키는 코드
    }
}

위처럼 예외를 발생시키는 코드가 있고, method1 내부의 method2 에서 예외가 발생하고 있을 때, fillInStackTrace는 함수의 호출 스택을 역추적 하면서 기록합니다.

method2 -> method1 의 순서를 따라, 마지막으로 호출된 메서드부터 기록을 시작하게 되는 것입니다.

이러한 stack trace는 깊이가 깊어질수록 많은 자원이 소모되어 성능을 저하시킵니다.

fickleBoBo님께서 작성하신 것처럼 이렇게 많은 자원을 소모하는 예외 처리를 사용하는 대신 다른 값을 반환하도록 할 수 있지만, 불가피하게 예외 처리를 해야 한다면 어떻게 예외 처리에 소모되는 자원의 양을 줄일 수 있을까요?


fillInStackTrace의 재정의

단순히 예외가 발생하는 상황을 잡아내는 기능만 필요하고 예외의 추적기능이 필요하지 않다면 예외가 발생할 때 자동으로 실행되는 fillInStackTrace 메서드를 재정의하여 추적 기능을 제거함으로써 예외 처리 시 발생하는 자원을 크게 줄일 수 있습니다.

@Override 
public synchronized Throwable fillInStackTrace() {
   return this;
}

단, 모든 예외에 대해 위처럼 fillInStackTrace 기능을 제거한다면 얘기치 못한 오류를 해결하는 것에 어려움을 겪을 수 있으니 주의 깊게 설정할 필요가 있는 것으로 보입니다.

FickleBoBo commented 1 month ago

예외 처리에서 자원이 소모되는 이유에 대해 깊게 생각해보지 않았는데 실제로 예외가 발생하는 경우 성능에 문제가 될 수 있다는 점과 fillinStackTrace의 재정의로 자원 소모를 조절도 할 수 있다는 점이 상당히 흥미롭습니다. 최근 프로젝트를 진행하며 예외가 거의 발생하지 않는, 혹은 논리적으로 발생할 수 없는 상황에서 Optional 처리를 null로 하지 않고 문제 발생 시 예외를 던지도록 해서 클린 코드를 짜는게 문제가 없는지 고민이 있었는데 해당 내용을 참고해서 성능 테스트를 해봐도 좋은 경험이 될 것 같습니다!!