응답하지 않는 앱 디버그하기
다른 언어: English Español Português 中文
라인 브레이크포인트를 설정하는 방법, 값 로깅, 또는 식 평가 등을 가르치는 디버거 튜토리얼이 많이 있습니다. 이러한 지식만으로도 애플리케이션 디버깅에 많은 도구를 제공하지만, 실제 시나리오는 약간 까다롭고 더 고급 방법이 필요할 수 있습니다.
이번 글에서는 프로젝트에 대한 사전 지식이 많지 않아도 UI 동작 중지를 일으키는 코드를 찾는 방법과 즉시 결함이 있는 코드를 수정하는 방법을 배워보겠습니다.
문제
따라가려면 먼저 이 저장소를 복제하십시오: https://github.com/flounder4130/debugger-example
어떤 작업을 수행하면 복잡한 애플리케이션에서 멈춤이 발생하는 상황을 가정해 봅시다. 버그를 재현하는 방법을 알고 있지만 문제는 이 기능을 담당하는 코드 부분을 모른다는 것입니다.
우리 예제 앱에서는 Button N을 클릭하면 멈춤이 발생합니다. 그러나 이 작업을 담당하는 코드를 찾는 것은 그렇게 쉽지 않습니다:
디버거를 사용하여 이를 어떻게 찾을 수 있는지 살펴봅시다.
메서드 브레이크포인트
메서드 브레이크포인트의 장점은 클래스의 전체 계층 구조에 사용할 수 있다는 것입니다. 이것이 어떻게 우리에게 유용할까요?
예제 프로젝트를 보면 모든 작업 클래스가
Action
인터페이스에서 파생되었고,
이 인터페이스는 하나의 메서드인 perform()
만을 가지고 있다는 것을 알 수 있습니다.
이 인터페이스 메서드에 메서드 브레이크포인트를 설정하면 파생된 메서드 중 하나가 호출될 때마다 애플리케이션을 중지합니다. 메서드 브레이크포인트를 설정하려면 메서드를 선언하는 라인을 클릭하세요.
디버거 세션을 시작하고 Button N을 클릭하십시오. 애플리케이션은 ActionImpl14
에서 중지됩니다.
이제 이 버튼에 해당하는 코드가 어디에 위치하는지 알게 되었습니다.
이 글에서는 버그를 찾는 것에 집중하고 있지만, 이 기법은 큰 코드베이스에서 어떻게 작동하는지 이해하고자 할 때 많은 시간을 절약할 수 있습니다.
애플리케이션 일시 중지
메서드 브레이크포인트를 이용하는 접근법은 잘 작동하지만, 이는 우리가 부모 인터페이스에 대해 어떤 것을 알고 있다는 가정에 기초하고 있습니다. 이 가정이 틀리거나 다른 이유로 이 접근법을 사용할 수 없다면 어떻게 할까요?
우리는 심지어 브레이크포인트 없이도 이것을 할 수 있습니다. Button N을 클릭하고, 애플리케이션이 멈춤 상태일 때 IntelliJ IDEA로 돌아갑니다. 메인 메뉴에서 실행 | 디버그 액션 | 프로그램 일시 중지 (Run | Debugging Actions | Pause Program)을 선택합니다.
애플리케이션은 일시 중지되어, 우리는 스레드 및 변수 (Threads & Variables) 탭에서 스레드의 현재 상태를 검사할 수 있습니다. 이를 통해 애플리케이션의 현재 작업 상황을 이해할 수 있습니다. 애플리케이션이 멈춰 있기 때문에, 멈춤을 일으키는 메서드를 파악하고 호출 사이트를 추적할 수 있습니다.
이 접근 방식은 곧 언급하게 될 더 전통적인 스레드 덤프보다 일부 이점이 있습니다. 예를 들어, 이는 편리한 형태로 변수에 대한 정보를 제공하고 프로그램의 진행을 제어할 수 있게 해줍니다.
프로그램 일시 중지 (Pause Program)를 이용한 더 많은 팁과 트릭을 보려면 Breakpoints 없는 디버그 와 Debugger.godMode()를 참조하세요.
스레드 덤프
마지막으로, 디버거의 기능은 아니지만, 스레드 덤프를 사용할 수 있습니다. 이것은 디버거를 사용 중인지 여부와 관계없이 사용할 수 있습니다.
Button N을 클릭하십시오. 애플리케이션이 멈춰 있는 동안 IntelliJ IDEA로 돌아갑니다. 메인 메뉴에서 실행 | 디버그 액션 | 스레드 덤프 받기 (Run | Debugging Actions | Get Thread Dump)를 선택합니다.
왼쪽에서 사용 가능한 스레드를 스캔하면 AWT-EventQueue에서 문제가 발생하는 위치를 볼 수 있습니다.
스레드 덤프의 단점은 그것들이 만들어진 시점의 프로그램 상태에 대한 스냅샷만 제공한다는 것입니다. 스레드 덤프를 사용하여 변수를 탐색하거나 프로그램의 실행을 제어할 수 없습니다.
우리 예제에서는 스레드 덤프에 의존할 필요가 없습니다. 그러나 디버그 에이전트 없이 시작된 애플리케이션을 디버깅하려고 할 때와 같이 다른 경우에 유용할 수 있기 때문에 이 기법을 언급하고 싶었습니다.
문제 이해하기
디버깅 기법에 관계없이 우리는 ActionImpl14
에 도달합니다.
이 클래스에서는 누군가가 작업을
별도의 스레드에서 수행하려고 했지만
Thread.start()
와 Thread.run()
,
호출 코드와 같은 스레드에서 코드를 실행하게 만들었습니다.
IntelliJ IDEA의 정적 분석기는 설계 시간에 우리에게 이에 대해 경고조차 합니다:
무거운 작업(또는 이 경우에는 무거운 수면)을 수행하는 메서드가 UI 스레드에서 호출되어 메서드가 완료될 때까지 그것을 차단합니다. 그래서 우리가 Button N을 클릭한 후에는 일정 시간 동안 UI에서 어떤 것도 할 수 없습니다.
핫스왑(HotSwap)
버그의 원인을 발견했으니 이 문제를 해결해 봅시다.
우리는 프로그램을 중지시키고 코드를 다시 컴파일한 다음 다시 실행할 수 있습니다. 그러나 작은 변경 사항 때문에 전체 애플리케이션을 다시 배포하는 것은 항상 편리하지는 않습니다.
스마트하게 해결해 봅시다. 먼저 제안된 퀵 수정을 사용하여 코드를 수정합니다:
코드가 실행 준비가 되면 실행 | 디버그 액션 | 변경된 클래스 다시 로드 (Run | Debugging Actions | Reload Changed Classes)를 클릭합니다. 새로운 코드가 VM에 전달되었다는 것을 확인하는 풍선이 나타납니다.
애플리케이션으로 돌아가서 확인해 봅시다. Button N을 클릭해도 앱은 더 이상 멈추지 않습니다.
요약
추론과 디버거의 몇 가지 기능을 사용하여 프로젝트에서 UI 동작 중지를 일으키는 코드를 찾을 수 있었습니다. 그런 다음, 코드를 수정하는 데 다시 컴파일과 재배포에 시간을 낭비하지 않고, 실제 프로젝트에서는 길게 걸릴 수 있는 과정을 거치지 않았습니다.
이러한 기법이 유용하다고 생각되어 말씀해 주시면 좋겠습니다!
더 자세한 내용을 기대해 주세요!