메서드 호출 녹화
메서드 호출을 녹화하는 것은 프로파일러에게 가장 어려운 작업 중 하나입니다. 왜냐하면 이는 상충되는 제약 조건 하에서 작동하기 때문입니다: 결과는 정확하고 완전해야 하며, 측정된 데이터에서 도출한 결론이 잘못되지 않도록 매우 적은 오버헤드를 생성해야 합니다. 불행히도, 모든 유형의 애플리케이션에 대해 이러한 모든 요구 사항을 충족하는 단일 측정 유형은 없습니다. 이 때문에 JProfiler는 사용할 메서드를 결정하도록 요구합니다.
샘플링 대 계측
메서드 호출을 측정하는 것은 "샘플링"과 "계측"이라는 두 가지 근본적으로 다른 기술로 수행될 수 있으며, 각각 장점과 단점이 있습니다: 샘플링의 경우, 스레드의 현재 호출 스택이 주기적으로 검사됩니다. 계측의 경우, 선택된 클래스의 바이트코드가 수정되어 메서드 진입 및 종료를 추적합니다. 계측은 모든 호출을 측정할 수 있으며 모든 메서드에 대한 호출 횟수를 생성할 수 있습니다.
샘플링 데이터를 처리할 때, 전체 샘플링 주기(일반적으로 5ms)가 샘플링된 호출 스택에 할당됩니다. 많은 샘플이 있을 경우, 통계적으로 정확한 그림이 나타납니다. 샘플링의 장점은 드물게 발생하기 때문에 오버헤드가 매우 낮다는 것입니다. 바이트코드를 수정할 필요가 없으며, 샘플링 주기는 메서드 호출의 일반적인 지속 시간보다 훨씬 깁니다. 단점은 메서드 호출 횟수를 결정할 수 없다는 것입니다. 또한, 몇 번만 호출되는 짧은 실행 메서드는 전혀 나타나지 않을 수 있습니다. 이는 성능 병목을 찾고자 할 때는 문제가 되지 않지만, 코드의 세부적인 런타임 특성을 이해하고자 할 때는 불편할 수 있습니다.
반면에, 계측은 많은 짧은 실행 메서드가 계측될 경우 큰 오버헤드를 초래할 수 있습니다. 이 계측은 시간 측정의 고유한 오버헤드 때문에 성능 핫스팟의 상대적 중요성을 왜곡하지만, 핫스팟 컴파일러에 의해 인라인될 메서드가 이제 별도의 메서드 호출로 남아야 하기 때문이기도 합니다. 시간이 더 오래 걸리는 메서드 호출의 경우, 오버헤드는 무시할 수 있습니다. 주로 고수준 작업을 수행하는 좋은 클래스 집합을 찾을 수 있다면, 계측은 매우 낮은 오버헤드를 추가하며 샘플링보다 선호될 수 있습니다. JProfiler의 오버헤드 핫스팟 감지는 몇 번의 실행 후 상황을 개선할 수도 있습니다. 또한, 호출 횟수는 종종 중요한 정보로, 상황을 훨씬 쉽게 파악할 수 있게 해줍니다.
전체 샘플링 대 비동기 샘플링
JProfiler는 샘플링을 위한 두 가지 다른 기술적 솔루션을 제공합니다: "전체 샘플링"은 별도의 스레드로 수행되며, JVM의 모든 스레드를 주기적으로 일시 중지하고 스택 추적을 검사합니다. 그러나 JVM은 특정 "안전 지점"에서만 스레드를 일시 중지하므로 편향이 발생합니다. 고도로 멀티스레드 CPU 바운드 코드가 있는 경우, 프로파일된 핫스팟 분포가 왜곡될 수 있습니다. 반면에, 코드가 상당한 I/O를 수행하는 경우, 이 편향은 일반적으로 문제가 되지 않습니다.
고도로 CPU 바운드된 코드에 대한 정확한 숫자를 얻기 위해, JProfiler는 비동기 샘플링도 제공합니다. 비동기 샘플링에서는 프로파일링 신호 핸들러가 실행 중인 스레드 자체에서 호출됩니다. 프로파일링 에이전트는 네이티브 스택을 검사하고 Java 스택 프레임을 추출합니다. 주요 이점은 이 샘플링 방법에는 안전 지점 편향이 없으며, 고도로 멀티스레드 CPU 바운드 애플리케이션의 오버헤드가 낮다는 것입니다. 그러나 CPU 뷰에서는 "실행 중" 스레드 상태만 관찰할 수 있으며, "대기 중", "차단 중" 또는 "네트워크 I/O" 스레드 상태는 이 방법으로 측정할 수 없습니다. 프로브 데이터는 항상 바이트코드 계측으로 수집되므로 JDBC 및 유사한 데이터에 대한 모든 스레드 상태를 계속 얻을 수 있습니다.
비동기 샘플링은 호출 스택의 끝부분만 사용할 수 있는 잘린 추적으로 인해 고통받습니다. 이 때문에 호출 트리는 비동기 샘플링에 대해 핫스팟 뷰만큼 유용하지 않을 수 있습니다. 비동기 샘플링은 Linux와 macOS에서만 지원됩니다.
Java 17부터 JProfiler는 Hotspot JVM에서 샘플링을 위해 전역 안전 지점을 사용하지 않고 거의 제로 오버헤드로 전체 샘플링을 수행할 수 있습니다. 비동기 샘플링과 비교할 때, 여전히 단일 스레드에 대한 안전 지점 편향을 도입하지만, JVM의 모든 스레드에 대한 전역 안전 지점의 오버헤드는 더 이상 없습니다. 비동기 샘플링의 단점을 고려할 때, Java 17+에서는 전체 샘플링을 사용하는 것이 권장됩니다.
메서드 호출 녹화 유형 선택
프로파일링을 위한 메서드 호출 녹화 유형을 선택하는 것은 중요한 결정이며 모든 상황에 맞는 올바른 선택은 없으므로 정보에 입각한 결정을 내려야 합니다. 새 세션을 생성할 때, 세션 시작 대화 상자가 사용할 메서드 호출 녹화 유형을 묻습니다. 이후 언제든지 세션 설정 대화 상자에서 메서드 호출 녹화 유형을 변경할 수 있습니다.
간단한 가이드로, 애플리케이션이 스펙트럼의 반대쪽에 있는 두 가지 명확한 범주 중 하나에 속하는지 테스트하는 다음 질문을 고려하십시오:
프로파일된 애플리케이션이 I/O 바운드인가요?
이는 대부분의 시간을 REST 서비스 및 JDBC 데이터베이스 호출을 기다리는 많은 웹 애플리케이션의 경우입니다. 이 경우, 계측은 호출 트리 필터를 신중하게 선택하여 자신의 코드만 포함하도록 하는 조건 하에 최선의 옵션이 될 것입니다.프로파일된 애플리케이션이 멀티스레드 및 CPU 바운드인가요?
예를 들어, 이는 컴파일러, 이미지 처리 애플리케이션 또는 부하 테스트를 실행하는 웹 서버의 경우일 수 있습니다. Linux 또는 macOS에서 프로파일링하는 경우, 이 경우 가장 정확한 CPU 시간을 얻기 위해 비동기 샘플링을 선택해야 합니다.
그렇지 않으면, "전체 샘플링"이 일반적으로 가장 적합한 옵션이며 새 세션의 기본값으로 제안됩니다.
네이티브 샘플링
비동기 샘플링은 네이티브 스택에 접근할 수 있기 때문에 네이티브 샘플링도 수행할 수 있습니다. 기본적으로 네이티브 샘플링은 활성화되어 있지 않습니다. 왜냐하면 이는 호출 트리에 많은 노드를 도입하고 핫스팟 계산의 초점을 네이티브 코드로 이동시키기 때문입니다. 네이티브 코드에서 성능 문제가 있는 경우, 비동기 샘플링을 선택하고 세션 설정에서 네이티브 샘플링을 활성화할 수 있습니다.
JProfiler는 각 네이티브 스택 프레임에 속하는 라이브러리의 경로를 해결합니다. 호출 트리의 네이티브 메서드 노드에서 JProfiler는 네이티브 라이브러리의 파일 이름을 대괄호 안에 표시합니다.
집계 수준과 관련하여, 네이티브 라이브러리는 클래스처럼 작동하므로 "클래스" 집계 수준에서는 동일한 네이티브 라이브러리 내의 모든 후속 호출이 단일 노드로 집계됩니다. "패키지" 집계 수준은 네이티브 라이브러리와 상관없이 모든 후속 네이티브 메서드 호출을 단일 노드로 집계합니다.
선택한 네이티브 라이브러리를 제거하려면, 해당 네이티브 라이브러리에서 노드를 제거하고 전체 클래스를 제거하도록 선택할 수 있습니다.