본문 바로가기

Java/트러블슈팅

01. 애플리케이션의 문제점 찾기

💡 본 게시글은 라우렌치우 스필커 저자의 '자바 잘 읽는 법' 교재를 공부하고, 이에 대해 정리한 내용입니다.

들어가며

 일반적으로 소프트웨어 개발자는 새로운 기능을 구현하거나 에러를 조치하기 위해 코딩하는 것 보다 소프트웨어의 작동 방식을 이해하는 데  더 많은 시간을 씁니다. 개발자는 생산성을 높이기 위해 효율적인 조사 기법을 연마할 필요가 있고, 이를 통해 코드를 효율적으로 이해해야 합니다. 


1) 애플리케이션을 더 쉽게 이해하는 방법

 소프트웨어의 에러를 해결하기 위해서는 코드를 자세히 살펴봐야 합니다. 이 교재에서 필자는 코드 조사를 소프트웨어 기능의 특정한 동작을 분석하는 프로세스라고 정의합니다. 코드 조사는 소프트웨어의 문제를 찾아내는 것뿐만 아니라, 구조가 복잡한 요즘 애플리케이션의 작동 방식을 이해하거나 새로운 기술을 배우기 위한 목적을 가집니다.

애플리케이션의 코드를 분석하는 이유는 무엇일까?

  • 문제점 발견
  • 소프트웨어 이해(어떤 소프트웨어의 기능이 어떻게 작동되는지 알아야 개선할 수 있습니다.)
  • 기술 또는 라이브러리 학습

소프트웨어의 작동 방식을 조사하는 기법에는 어떤 방법들이 있을까?

로직을 쉽게 이해하기 위해서는 디버거(어떤 라인에서 실행을 잠깐 멈추고 데이터가 어떻게 변하는지 관찰하면서 각 커맨드를 수동으로 실행하는 도구)를 사용하여 어떤 입력이 주어지면, 어떤 식으로 처리가 되는지 라인별로 관찰하면 됩니다. 

하지만 요즘 애플리케이션은 대부분 라이브러리나 프레임워크 같은 디펜던시를 가지고 있어서 소스코드를 봐도 따라가기가 어렵습니다. 이럴 때 프로파일러를 이용하면 어떤 코드가 실행되는 지 식별함으로써 조사의 출발점을 결정할 수 있습니다.

또한 앱 크래시(애플리케이션이 갑자기 비정상 종료되는 현상)가 일어난다면 사후 조사를 통해 원인을 파악하고 애플리케이션을 개선해야 합니다. 사후 조사는 로그, 힙 덤프, 스레드 덤프 등의 트러블 슈팅 도구를 사용하여 수행합니다.


2) 일반적인 코드 조사 시나리오

(1) 어떤 코드나 소프트웨어 기능이 예상했던 것과 다른 결과가 나올 때

시나리오 1: 단순 케이스

  • 디버거를 사용하면 커맨드가 실행되기 전에 잠깐 멈추고, 하나씩 수동으로 실행해보면서 애플리케이션의 로직상 데이터가 어떻게 바뀌는 지 확인할 수 있습니다.

 

시나리오 2: 어디서부터 디버깅을 시작해야 할 지 모르는 경우

  • 프로파일러로 브레이크포인트를 추가할 만한 코드 라인의 스코프(범위)를 좁혀가야 합니다.
  • 프로파일러는 앱이 실행되는 동안 어떤 코드가 실행되는지 식별하는 도구입니다. 

 

시나리오 3: 멀티스레드 앱

  • 다중 스레드, 즉 멀티스레드 아키텍처를 기반으로 한 로직을 처리할 때, 간섭에 민감한 편이어서 디버거를 사용할 수 없는 경우가 많습니다.
  • 하이젠버그 실행. 즉, 멀티스레드 앱이 실행될 때 디버거가 간섭을 일으키면 앱 작동 방식이 달라질 수 있습니다. 이러한 변화가 일어나면 조사하려는 앱의 동작을 처음부터 정확하게 조사하기 어렵습니다.
  • 대안으로는 앱에서 로깅을 사용하는 방법, 디버거로 조사할 수 있게 스레드 수를 1개로 줄이는 방법을 생각해볼 수 있습니다.

 

시나리오 4: 주어진 서비스에 잘못된 호출 보내기

  • 먼저, 코드의 어느 부분이 요청을 보내는지 찾아봅니다. 이 부분을 이미 알고 있다면 디버거를 사용해서 앱이 어떻게 요청을 생성하는지 살펴보고 어디가 잘못됐는지 확인합니다. 
  • 앱의 어느 코드가 요청을 전송하는지 모르면 프로파일러를 사용해서 찾을 수도 있습니다.
  • 앱이 요청을 주고받는 위치를 특정하기 곤란한 복잡한 경우라면 스텁(가짜 앱)을 만들어 앱이 호출되는 컴포넌트를 대체하여 제어하면 (ex. 무기한 대기) 조사를 한결 수월하게 수행할 수 있습니다. 

(2) 디펜던시로 사용하는 기술이 어떻게 작동되는지 모르는 경우 

 코드를 분석하는 조사 기법의 또 다른 용도는 특정 기술의 작동 원리를 배우는 것입니다. 어떤 기술을 배우든지 작성한 코드를 검토하는 시간에 아낌없이 투자해야 합니다. 항상 프레임워크의 코드를 더 자세히 살펴보고 디버깅하려는 노력을 기울이면, 훨씬 더 나은 개발자로 성장할 것입니다. 


(3) 앱 속도 저하 같은 성능 이슈가 발생하는 경우

성능 문제의 원인은 보통 프로파일러를 사용하면 쉽게 밝혀낼 수 있습니다. 프로파일러는 각 커맨드의 실행 시간이 프로파일러 화면에 표시되므로 속도 저하 문제가 어디서 발생하는지 쉽게 파악할 수 있습니다.


(4) 앱이 갑자기 중단되는 경우(앱 크래시 발생)

앱 크래시는 보통 두 가지 형태로 일어납니다.

  • 앱이 완전히 멈추는 경우
  • 실행은 계속되지만 요청에 응답하지 않는 경우

 앱이 완전히 멈춘 경우, 복구 불가능한 에러가 발생했다는 뜻입니다. 이 경우에는 대부분 메모리 에러 때문에 일어납니다. 자바는 힙 메모리가 가득 차 앱이 더 이상 작동하지 않으면 OOM 에러(OutOfMemory Error, 메모리 부족 에러)를 발생합니다. 힙 메모리 문제를 조사하고자 할 때, 힙 덤프를 사용합니다. 힙 덤프는 OOM 에러 메시지가 표시되고 앱 크래시가 발생할 때마다 이런 스냅숏이 자동 생성되도록 자바 프로세스를 구성할 수 있습니다. 

 앱은 계속 실행되고 있지만 요청을 해도 응답이 없는 경우, 안에서 무슨 일이 일어나고 있는 지 분석하는 스레드 덤프를 사용하는 것이 좋습니다.  스레드 덤프는 덤프를 생성할 당시 실행 중이던 스레드에 관한 세부 정보를 제공합니다. 스레드 상태와 스택 트레이스는 물론, 이를 통해 스레드가 어떤 코드를 실행 중이었는지, 무엇 때문에 스레드가 차단되었는지 확인할 수 있습니다.

'Java > 트러블슈팅' 카테고리의 다른 글

02. 디버깅 기법으로 앱 로직 이해하기  (0) 2024.05.31