IntelliJ profiler 소개 (with JFR)
JFR/JMC와 IntelliJ Profiler를 함께 정리해 본다.
JFR + JMC 간단 소개
이런 JVM 정보가 필요할 때가 있다. 메모리 누수, 경합, 병목을 추적할 때 특히 그렇다.
- CPU 사용량 분석
- 메모리 사용량 추적 (Heap, GC 이벤트 등)
- 스레드 동작 분석
- JVM 내부 이벤트 모니터링
- 네트워크/파일 I/O, JDBC 호출 추적
- ...
이럴 때 필요한 것이 진단 도구다. 오라클 HotSpot JVM은 기본적으로 JFR을 제공하고, 녹화된 파일을 JMC로 분석한다. 즉, 두 도구는 세트로 보는 게 편하다.
- JFR(java flight recorder) // 녹화 도구
- JMC(java mission control) // GUI 분석기
두 도구를 소개하는 페이지들은 표현이 제각각이었다. 블랙박스, 진단도구, 심층분석기, 프로파일러, 이벤트 수집 도구 등. 여기서는 그냥 진단 도구라고 부르겠다. https://docs.oracle.com/javacomponents/jmc-5-4/jfr-runtime-guide/about.htm#JFRUH170 https://blogs.oracle.com/javakr/post/diag-tool https://www.baeldung.com/java-flight-recorder-monitoring
진단까지의 흐름은 약간 번거롭다. 도구가 어렵다기보다 설치/명령어/파일 포맷이 번거롭다.
- 애플리케이션 실행
- JFR 실행
- 분석할 핸들러 실행
- JFR 종료 (
.jfr파일 생성) .jfr파일을 JMC에서 열어 분석
절차를 마치면 JMC로 프로파일링(심층분석)이 가능하다.

참고로 JFR은 실행 중인 JVM도 pid만 있으면 녹화할 수 있다. 그리고 대부분의 이벤트는 오버헤드가 거의 없다고 한다. (참고)
즉, 실행 중인 인스턴스에서 .jfr만 추출해 와도 로컬에서 분석이 가능하다.
$ jcmd <pid> JFR.start name=Recording1 settings=default
$ jcmd <pid> JFR.dump filename=recording.jfr
$ jcmd <pid> JFR.stop애플리케이션 시작 시점에 옵션으로 녹화를 붙이는 것도 가능하다.
다만 옵션이 많아서 매번 man을 봐야 하는 게 번거롭다.
-XX:StartFlightRecording:disk=true,\
filename=svc/sandbox/service.jfr,\
maxage=12h,\
settings=profile
요약하면, JFR + JMC는 매우 유용하지만 약간 번거로운 진단 도구다.
IntelliJ Profiler 소개
IntelliJ Profiler는 IDE 내장 진단 도구다. JFR + JMC를 대체할 수 있을 만큼 편하다.
장점:
- JFR 커맨드라인을 몰라도 된다.
.jfr파일 위치를 몰라도 된다. (내부적으로 JFR 사용)- JMC 같은 GUI 도구를 따로 설치할 필요가 없다.
- IDEA 안에서 소스와 함께 볼 수 있다.
자세한 설명은 아래를 참고.
IntelliJ Profiler 핸즈온
아래처럼 옵션 실행만 하면 진단이 시작된다.

이미 실행 중인 프로세스도 녹화 가능하다.
Attach...로 PID를 찍어 시작하는 방식이다.
메모리 스냅샷, 덤프, 라이브 차트 기능도 있어서 매우 유용하다.

JMC와 차별화되는 장점은 소스 코드의 병목 구간을 시각화해서 볼 수 있다는 점이다.

전체 흐름은 아래 튜토리얼로 충분히 익힐 수 있다.
유용한 기능 몇 가지 더
메모리 보기 기능
아래 코드는 static 변수에 무한으로 계속 넣는 코드다. 당연히 메모리는 계속 늘어난다. 이때 메모리 할당 기준으로 스위치해서 보면 추적이 쉬워진다.

라이브로 메모리와 CPU를 추적할 수도 있다. Heap Memory가 계속 늘어나는 모습을 볼 수 있다.

JVM events도 확인 가능하다. GC가 몇 번 일어났는지도 보여줘서 메모리 릭 추적에 도움이 된다.

아쉽게도 메이저 GC 여부는 안 보이는 듯하다. old 영역의 사이즈도 확인되지 않는다. 시간을 더 길게 테스트하면 다른 특이점을 볼 수 있을지도 모르겠다. heap 메모리를 아주 작게 설정해서 테스트해 보는 것도 방법이다.
재현용 코드는 아래에 첨부한다.
public class MemoryLeakExample {
private static final List<byte[]> memoryLeakList = new ArrayList<>();
public static void main(String[] args) {
while (true) {
byte[] leak = new byte[1024 * 1024]; // 1MB 배열 생성
memoryLeakList.add(leak);
System.out.println("Allocated: " + memoryLeakList.size() + " MB");
try {
Thread.sleep(100); // 0.1초 대기
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}스냅샷 기능 (덤프 및 분석)
실행 중인 JVM에 스냅샷을 찍거나 덤프를 뜰 수도 있다.

덤프를 분석하면, byte[] 용량이 압도적으로 큰 것도 바로 확인된다.

JFR과 JMC는 과거의 유산 아니었나?
내 기억에선 한동안 인기가 없었다. 가장 큰 이유는 유료였다. (Java 8까지 유료, 11부터 오픈소스화) 그리고 효용이 낮다고 느껴지는 시기도 있었다.
- 스케일아웃이 너무 쉬워져서 심층분석 최적화의 ROI가 낮아짐
- 메모리 릭 같은 케이스는 보통 힙 덤프로 대응
- 심층분석은 1개 JVM에 대해서만 가능
- CPU/Mem은 뉴렐릭, 데이터독 같은 통합 모니터링에 의존
- AWS에서 인스턴스 메트릭을 쉽게 제공
하지만 지금도 계속 관리되는 기능이라 신뢰가 간다.
Java 14부터는 .jfr 파일을 스트리밍해 뉴렐릭 같은 도구가 가져갈 수 있는 API가 추가됐다.
Java 21부터는 터미널에서도 간편하게 볼 수 있는 view 커맨드가 생겼다고 한다.
마치며
JFR/JMC는 병목 추적이나 메모리 릭 분석에 여전히 유용하다. 다만 설치와 명령어가 번거롭다. IntelliJ Profiler는 그 과정을 훨씬 줄여준다. 특히 IDEA 안에서 소스와 함께 볼 수 있다는 점이 큰 장점이다.