JVM(Java Virtual Machine) profiling 툴인 VisualVM에 대한 내용을 정리합니다.
개발된 Applicaiton을 CPU, Memory, Thread 등의 이슈로 분석이 필요할 수 있습니다.
APM을 통해 확인이 가능하지만 로컬 환경에서 개별 분석을 수행하고 싶을 경우 유용할 것이라 판단됩니다.
마이클 A.잭슨은 자신의 저서 Principals of Program Design(프로그램 설계의 원리)에서 다음과 같은 최적화 관련된 최고의 규칙 두 가지를 제시했다.
위 두 규칙 이면에 있는 아이디어는 간단하다.
개발 과정에서 소프트웨어는 변화한다. 이 때문에 시스템이 개발되기 전까지는 시스템 설계 방법에 대한 정확한 의사 결정이 사실상 불가능하다.
시스템이 개발된 이후에야 성능 병목현상을 테스트하고, 필요에 따라 이를 해결할 수 있다.
이런 접근 방식을 취하지 않으면 두 번째로 좋아하는 격언인 윌리엄 울프의 최적화와 관련된 격언대로 될 위험이 있다.
맹목적인 어리석음을 비롯한 그 어떠한 다른 이유보다도, 효율성이라는 이름으로 더 많은 컴퓨팅과 관련된 죄가 저질러진다.
JVM이 어떤 상태인지 파악할 수 있는 도구이며
CPU 및 메모리 사용량, 메서드 실행 시간, 스레드 관리, 가비지 컬렉션과 관련된 세부 정보를 제공한다.
자바 9 이전에는 VisualVM이 JVM과 함께 제공되었으나 자바 9부터는 깃허브에서 다운로드해야 사용할 수 있다.
다운로드 > 압축 해제 > bin 폴더 visualvm 실행
Applications 메뉴
메뉴명 | 설명 |
---|---|
Local | Local에 구동 중인 JVM |
Remote | Remote상에 구동 중인 JVM |
VM Corecumps | 미리 생성해 둔 자바 VM 코어 덤프를 로드 |
JFR Snapshots | JFR로 생성한 스냅샷 로드 |
Snapshots | VisualVM을 사용해서 캡처한 특정 시점의 VM 상태 스냅샷 로드 |
기본적으로 VisualVM을 실행할 경우 별도의 작업 없이도 구동 중인 JVM이 목록에 보여진다.
(이미지 설명: application을 구동 후 왼쪽 메뉴 더블클릭 한 상태)
실행 중인 자바 애플리케이션의 개요를 제공한다.
여기에는 main 클래스, 애플리케이션 이름, 프로세스 ID, 시작 시 JVM에 전달된 아큐먼트가 포함된다.
추가적으로 설명하자면 Overview 탭에는 현재 분석 중인 자바 프로세스의 정보가 표시된다.
CPU 사용률, 메모리 사용률(Heap과 PermGen), 로딩된 클래스 수, 수행 중인 데몬 스레드 수를 보여주는 차트를 표시한다.
애플리케이션의 가비지 컬렉션을 수행할 수 있으며, 추후 분석을 위해 힙 덤프를 생성할 수도 있다.
Heap Dump 버튼을 클릭하면 Heap Dump가 수행되며
Dump 파일의 내용을 별도의 탭으로 표시한다.
Objects 항목을 선택하면 Heap Dump 수행 시점의 객체 정보를 확인할 수 있다.
→ 메모리가 특정 시점에 과도하게 늘어날 경우 그 시점의 Heap Dump를 분석하여 어떠한 객체인지 판단할 수 있다.
Heap Dump를 수행할 경우 순간적으로 Application 성능 지연이 발생할 수 있음에 유의한다.
애플리케이션이 실행한 모든 스레드와 해당 스레드가 어떤 작업을 하고 있는지와 관련된 정보를 표시한다.
해당 데이터는 타임라인 형식, 테이블 형식, 세부 정보 형식으로 표시된다.
사전 지식으로 Thread의 상태는 Running, Sleeping, Wait, Park, Monitor로 구분되어 진다.
1개의 스레드는 정상적으로 실행(Running)되고 있고, 다른 스레드는 객체에 Monitor를 획득할 수 없어서 Lock이 걸린 상태로 대기하고 있다.
Stack Trace를 보아야 정확한 스레드의 상태를 알 수 있지만, 1번 스레드가 Lock을 해제하여야 다른 스레드가 실행될 수 있는 형태일 가능성이 높다.
2개 이상의 스레드가 동시에 Monitor가 걸려 있는 경우는 Dead Lock이 걸려 있을 가능성이 있다.
정확한 Dead Lock 상태 유무는 실제 Stack Trace를 보고 스레드들이 동일한 객체에 대해 Monitor Lock을 소유하려고 경쟁하고 있는지를 확인해야 한다.
참고로 Lock이든 Dead Lock이든 CPU를 많이 사용하지는 않는다.
Deadlock이 감지될 경우 Thread Dump 수행을 통해 상세 정보를 확인하라는 경고 문구가 발생된다.
Wait이 걸려 있는 경우도 역시 특정 객체에 대한 Lock을 확보하지 못해서 대기하고 있을 가능성이 높다.
앞의 Monitor와의 차이라고 하면, Wait 상태는 특정 스레드가 객체에 대한 Monitor Lock을 다 사용한 뒤, notify 신호를 받기를 기다리는 상태이다.
Sleep은 Monitor Lock과 관계없이 일정시간 동안 대기하는 반면에 Wait은 Lock으로 인해 깨우는 신호를 받을 때까지 대기한다는 차이가 있다.
Monitor Lock을 소유한 스레드의 경우에 Sleep한 경우 Monitor Lock을 해제하지 않고 대기하는 반면, Wait한 경우는 Monitor Lock을 풀어서 다른 스레드가 Monitor Lock을 획득할 수 있도록 한다.
Running 상태의 스레드도 2가지 케이스가 있을 수 있다. 정상적으로 메소드를 수행하면서 오래 수행되고 있는 경우로 이때는 CPU를 사용하여 실행이 된다.
하지만, 네트워크로부터 데이터를 읽기 위해 데이터 수신을 기다리고 있는 경우는 데이터가 수신될 때까지 정상적으로 실행되지 않고 무한정 대기하는 상태일 수 있다.
Stack Trace를 보면 어떤 일(메소드 수행)을 하면서 Running 상태인지를 살펴보면 스레드의 상태를 파악하고 문제를 찾아낼 수 있다.
Thread Dump를 수행할 경우 순간적으로 Application 성능 지연이 발생할 수 있음에 유의한다.
Thread Dump 버튼을 클릭하면 실행 중인 JVM의 Full Thread Dump가 수행되며
Dump 파일의 내용을 조회할 수 있다.
애플리케이션의 CPU 사용률과 메모리 할당 상태를 순간적으로 잡아내 스냅샷을 만들 수 있다.
CPU 사용률은 어떤 메서드가 얼마나 오래 실행되는지를 보여준다.
메모리 사용률은 어떤 클래스가 얼마나 많은 메모리를 사용하는지 보여준다.
애플리케이션의 CPU, Memory, JDBC, Locks에 대한 프로파일링 기능을 제공한다.
Sampler에 비해 성능을 많이 소모하며 Settings 설정을 통해 좀 더 상세한 프로파일링 설정이 가능하다.
VisualVM은 기본 제공 기능을 확장할 수 있는도록 더 많은 플러그인을 제공한다.
Tools > Plugins
Available Plugins > Install