티스토리 뷰

Java & Kotlin

[JVM] Async-Profiler 소개 및 IntelliJ에서 프로파일링 결과 분석하는 방법

망나니개발자 2024. 3. 5. 10:00
반응형

 

 

 

1. Async-Profiler 소개 및 사용 방법


[ Async-Profiler란? ]

async-profiler는 오픈소스 프로젝트로, Safepoint bias 문제를 겪지 않는 자바 전용 저오버헤드(low-overhead) 샘플링 프로파일러이다. Safepoint란 GC 작업을 진행하면서 사용되지 않는 객체들을 식별하는데, 이때 애플리케이션이 안전한 지점으로 이동하여 GC를 진행할 수 있는 지점을 safepoint라고 한다. 그리고 Safepoint bias 문제란 간단히 요약하면 샘플링 프로파일러에 의한 분석 샘플이 특정 위치로 편향되는 문제를 의미한다. 기존의 많은 자바 샘플링 프로파일러들은 Safepoint bias 문제에 의해 정확한 분석을 해주지 못했기 때문에 상당히 아쉬운 부분이 많이 있었다.

하지만 async-profiler는 이러한 문제 없이 스택 트레이스(stack trace)를 수집하고 메모리 할당을 추적하기 위한 HotSpot VM 전용 API를 제공한다. 이를 통해 런타임에 다음과 같은 것들을 추적할 수 있다.

  • CPU 사이클
  • 자바 힙 메모리 할당
  • 캐시 미스, 브랜치 미스, 페이지 폴트, 컨텍스트 스위치와 같은 하드웨어 및 소프트웨어 성능 카운터
  • 자바 객체 모니터와 재진입 잠금을 포함한 콘텐츠 잠금 시도 횟수

 

 

먼저 대표적으로 CPU 프로파일링의 경우에는 기본적으로 자바 메소드에 더해 네이티브 메소드, JVM 코드와 커널 함수까지 포함된 스택 트레이스 샘플을 수집한다. 메모리 프로파일링의 경우 가장 많은 양의 힙 메모리가 할당된 호출 사이트를 수집하도록 구성할 수 있다. async-profiler는 Bytecode Instrumentation나 성능에 큰 영향을 줄 수 있는 Dtrace probe(운영 시스템의 커널과 응용 프로그램 문제를 실시간으로 해결하기 위해 sun사가 개발한 동적 트레이싱 프레임워크)와 같은 침투적인(intrusive) 기술을 사용하지 않는다. 또한 Escape Analysis(객체의 포인터(참조)가 서브 루틴 밖으로 전파되는지를 분석하는 기술)나 allocation elimination(코드에서 불필요한 메모리를 정리하는 최적화 기법)과 같은 JIT 최적화에 영향을 주지 않는다. 오직 실제 힙 할당만 측정한다.

 

 

 

[ Async-Profiler 사용 방법 ]

만약 프로파일링 기능을 운영서버에서 얻고 싶다면 다음과 같이 async-profiler를 설치하고, 명령어를 실행해주면 된다. 그리고 실행 결과로 나온 파일을 IntelliJ에서 열면 된다.

wget https://github.com/async-profiler/async-profiler/releases/download/v3.0/async-profiler-3.0-linux-x64.tar.gz 
    && tar xzvf async-profiler-3.0-linux-x64.tar.gz

// PID가 1인 Java 프로세스의 CPU와 메모리 할당 이벤트를 60초 동안 수집하고, 그 결과를 profile.jfr 파일에 저장함
./profiler.sh -e cpu,alloc -f profile.jfr -d 60 1

// PID가 7인 Java 프로세스의 Interval Timer 이벤트를 10초 동안 수집하고, 결과를 profile.jfr 파일에 저장함
./profiler.sh --fdtransfer -e itimer -f profile.jfr -d 10 7

 

 

 

 

 

 

 

2. IntelliJ에서 프로파일링 결과 분석하는 방법


[ 로컬 환경에서 프로파일링하기 ]

IntelliJ Ultimate를 사용하고 있다면, 다음과 같이 로컬 환경에서 프로파일링과 함께 서버를 실행할 수 있다. 비록 async-profiler는 아니지만 인텔리제이가 제공하는 프로파일러 역시 유용하다.

 

 

프로파일링할 기능들을 호출한 후에 Stop Recording 버튼을 클릭하면 프로파일링을 종료할 수 있다.

 

 

그러면 다음과 같이 프로파일링 결과를 볼 수 있다.

 

 

 

 

 

 

 

 

[ 분석 가능한 항목 ]

  • CPU Time
    • I/O, 잠금 대기, 컨텍스트 스위칭 등을 제외한, 실제 CPU 작업에 해당하는 샘플의 하위 집합
    • 알고리즘 복잡성 개선과 같이 최적화를 통해 최대의 효과를 얻을 수 있는 CPU 집약적 작업 식별에 유용함
  • Total Time
    • Sleep 상태의 스레드를 포함한 모든 샘플에 적용됨
    • I/O, 컨텍스트 스위칭 오버헤드, 동기화(synchronization) 등 체감 성능과 실제 런타임을 고려하는 데 유용함
    • 외부 요인이나 최적이 아닌 동시성으로 인해 속도가 느려질 수 있는 섹션을 파악할 수 있
  • Memory Allocations
    • 메모리 할당 이벤트에 해당하는 샘플의 하위 집합
    • 원시값 박싱, 객체 생성 등 양을 최적화하여 최대의 이점을 얻을 수 있는 메모리 집약적인 작업 식별에 유용함

 

 

만약 IntelliJ Profiler가 아닌 Async-Profiler의 결과를 확인한다면 볼 수 있는 항목이 다르다. Async-Profiler의 결과로는 CPU Samples와 Memory Allocations를 확인할 수 있는데, 분석하는 방법은 크게 다르지 않다.

 

 

 

 

[ 프로파일링 결과 분석하는 방법 ]

프로파일링 결과로 확인할 수 있는 탭 역시 여러 가지가 있다.

  • Flame Graph
  • Call Tree
  • Method List
  • Timeline
  • Events

 

 

 

 

 

Flame Graph

먼저 Flame Graph 같은 경우에는 다음과 같은 특징을 갖고 있다. Flame Graph는 스레드별로 그룹화되어 있다. 전체 스레드가 병합된 결과를 확인할 수도 있고, 특정 스레드를 선택하여 자세히 조사할 수 있다.

 

 

여기서 Flame Graph의 각 항목은 다음과 같다.

  • y축: 호출 스택
  • x축: 리소스를 가장 많이 소비하는 함수 순서(사용률이 높을수록 왼쪽에 위치하며 너비가 넓음)
  • 색상: 파란색은 native call, 노랑색은 java call, 회색은 library call

 

 

예를 들어 다음과 같은 Flame Graph가 있다고 하자. 해당 그래프를 보면 다음과 같은 분석 결과를 얻을 수 있다.

  • main의 실행에는 a 및 b 메서드가 기여했고, a는 다음으로 c를 호출함
  • c는 주로 ArrayList에 요소를 추가하는데, 이때 대부분 grow를 처리하는데 많이 소요함
  • b는 대부분의 경우 IndexOutOfBoundsException을 처리하므로, 예외 발생 위치 조사와 조치 등이 필요함

 

 

Flame Graph에서 우클릭하면 나오는 Focus on method in Call Tree를 활용하면 해당 소스로 바로 이동할 수 있다.

 

 

그리고 연관된 코드로 넘어가면 다음과 같이 IntelliJ에서 분석 결과를 바로 확인할 수 있다. 리소스를 가장 많이 소비하는 메서드에는 빨간색 레이블과 함께 불 아이콘이 표시된다.

 

 

 

 

Call Tree

리소스 사용량이 높은 순서로 호출 스택이 정렬되어 있다.

 

 

 

Method List

Method List는 프로파일링된 데이터의 모든 메소드를 수집하여 누적 샘플 시간별로 정렬한다. 항목은 samples와 own samples로 나뉘어 지는데, 각각 다음과 같이 구별하면 된다.

  • allocation size: 해당 메서드 전체의 결과
  • own allocation size: 하위 메서드를 제외하고 해당 메서드 자체만의 결과

 

 

 

여기서 크게 3가지 탭을 확인할 수 있는데, 각각 다음과 같다.

  • Back Traces: 메서드 호출자의 계층 구조를 보여주며, 이를 통해 선택한 메소드를 호출하는 메소드를 추적할 수 있음
  • Merged Calles: 메서드의 호출 계층 구조 아래 메서드를 요약한 호출 트리
  • Calle List: 호출 계층 구조에 따라 메서드를 요약한 메서드 목록

 

 

 

 

아마 위의 설명 만으로는 충분히 애플리케이션을 분석하기 어려울 수 있다. 따라서 다음 포스팅에서 실제 예시를 통해 코드를 분석하는 방법을 알아보도록 하자.

 

 

 

 

 

 

관련 포스팅

  1. Async-Profiler 소개 및 IntelliJ에서 프로파일링 결과 분석하는 방법
  2. 예시로 살펴보는 IntelliJ 프로파일링 결과 분석 및 성능 최적화 방법

 

 

 

 

 

 

 

 

참고 자료

 

 

 

 

 

반응형
댓글
반응형
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
TAG more
«   2024/05   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
글 보관함