* 가상 머신 상태 모니터링과 문제 해결에 쓰이는 주된 도구에는 상용 인증 도구 (JMC/ JFR. 개인 목적에서는 무료이나 상용 환경에서는 비용 지불 필요), 공식 지원 도구, 실험적 도구 세 범주가 있다.
* 도구들은 크기가 매우 작은게특징, 자바로 구현됨. 프로덕션 환경에서 사용되기에 부담이 없도록
1. JPS
* ps 명령어처럼, 동작 중인 가상 머신 프로세스 목록을 보여주며, 각 프로세스에서 가상 머신이 실행한 메인 클래스의 이름과 로컬 가상 머신 식별자(LVMID)를 알려줌.
2. JSTAT
* 가상 머신의 다양한 작동 상태 정보를 모니터링 하는데 사용
* 가상 프로세스의 클랫스 로딩, 메모리, GC, JIT 컴파일과 같은 런타임 데이터 볼 수 있음
$ jstat -gcutil 5404 (-gc 명령어는 힙 상태 모니터링 위주이지만, 이건 전체 공간 사용률에 초점)
S0 S1 E O M CCS YGC ...
0 87 31 61 97 92 17 ...

* 위와 같이 나온다면, 신세대의 에덴 공간을 31.15% 사용중, 두 생존자 공간 중 하나의 87% 정도를 사용 중이고, 구세대는 61% 사용중 이런 정보를 알 수 있다.
3. JINFO
* 가상 머신의 다양한 매개 변수를 실시간으로 확인 / 변경하는 도구
$ jinfo -flag ConGCThreads 1444 (ConGCThreads 값 출력)
-XX:ConGCThreads=2
4. JMAP
* 힙 스냅숏을 파일로 덤프해 주는 자바용 메모리 맵 명령어. LVMID 전달을 필요로 한다 ($ jmap [options vmid)
5. JHAT
* JMAP 에서 나온 힙 스냅숏 분석하는 도구. 작은 웹 서버를 내장하고 있어서 브라우저로 열 수 있지만 많이 사요앟진 않음
>> 힙 스냅숏 덤프 파일을 보통 다른 기기로 복사해서 분석하기 때문)
>> 분석이 단순한 편
6. JSTACK
* 스레드 스냅숏을 생성하는데 쓰이는, 스택 추적 도구. 스레드가 장기간 멈춰 있을 때 원인을 찾기 위해 생성

* 위와 같이 정말 많은 정보 알려주고, 각 스레드별 상태를 알려줌 (우선 순위, CPU 사용 시간, 경과 시간, 스레드 상태, 호출 스택 등등)
GUI 도구
* JDK는 GUI 도구 지원하는데, 대표적으로 JConsole, JHSDB, VisualVM, JMC
1. JHSDB
* SA를 통해 프로세스 외부에서 디버깅할 수 있는 도구 (SA는 핫스팟 가상 머신이 제공하는 API 집합, JVM의 런타임 정보 제공)
* JHSDB 를 실행하면 여러 옵션들이 있는데, Tools 에 Heap Parameter, Inspector 등등의 기능들이 있다
static class A {
static ObjectHolder staticObj = new ObjectHolder();
ObjectHolder instanceObj = new ObjectHolder();
void foo(){
ObjectHolder localObj = new ObjectHolder();
...
}
}
* 위와 같은 사례에서, staticObj, instanceObj, localObj 가 각각 어디에 저장되는지 (가르키는 객체가 아닌 변수 자체) 분석해볼 수 있다 (테스트 프로세스의 아이디를 얻어온 다음, $jhsdb hsdb - -pid {PID} 로 실행)
* 그럼 JHSDB 창이 뜨는데, 여기서 에덴의 시작주소와 끝 주소를 알아둔 다음, CMD Line 에 $ scanoops <시작주소> <끝주소> ObjectHolder(클래스경로) 를 치면 해당 클래스로 생성된 객체들이 해당 주소 안에 어디어디 존재하는지 알려줌. 에덴 주소 안에 모두 static, instance, local Obj 들이 있음
* Inspector 를 이번엔 실행해서, 위에서 얻은 객체의 주소를 입력해보면, 객체 헤더와 객체 메타데이터 (상속 관계, 인터페이스 관계, 필드 정보, 메서드 정보, 런타임 상수 풀 포인터 등등) 를 가리키는 포인터를 보여준다.

* Compute Reverse Ptrs 기능을 통해서는 해당 객체를 참조하는 포인터를 찾을 수 있다 (근데 명령어를 쓰는건지 메뉴를 실행하는건지 잘 모르겠음)
hsdb> revptrs <위에서 찾은 객체 주소>
Computing reverse pointers ...
...
Oop for java/lang/Class @ <이 Class 인스턴스의 주소>
* 이 부분 무슨 소린지 잘 모르겠음.. 참조를 타고 타면서 계속 정보를 알아내는 것 같은데.. 처음에 어디에 저장하는지 알 수 있다 부분부터,,, null 이 나왔으면 갑자기 뭘 더 하는데 그것도 뭔지 모르겠음.
2. JConsole
* JMX에 기반한 GUI 모티러이 및 관리 도구. 실행시 실행중인 가상 머신 프로세스들을 찾아줘서, 로컬 프로세스를 연결하거나, 원격 서버 정보를 통해 원격 모니터링도 가능

메모리 모니터링
fillHeap(){
// 대충 자바 힙에 64KB/50ms 의 속도로 총 1000개의 데이터를 채워 넣는 코드
// 다 채워넣은 이후에는 System.gc() 로 GC 호출 후 대기 (연결 유지를 위함)
}

* 채워졌다 줄었다 (줄어드는 것은 아마 구세대로 보내는 것?) 를 반복하다가 GC 이후에는 꺠끗하게 신세대의 에덴 / 생존자 공간이 비워지는 것을 볼 수 있다. 이에 따른 두가지 질문을 생각해볼 수 있다
>> Xms, Xmx 를 통해 자바 힙을 100MB 로 제한했는데, 이는 신세대 크기 명시 용도가 아니다. 이 상황에서 JConsole 을 통해 신세대의 용량을 예측할 수 있는가?
>> System.gc 이후 힙 메모리가 최대치를 유지하는 이유는? gc 를 통해 힙의 객체를 회수하도록 하기 위해선?
* 위 사진에 따르면 에덴의 크기는 27,328KB 임. 에덴과 생존자 공간의 비율은 기본 8:1 (SurvivorRatio 를 통해 변경은 가능) 이므로 신세대 전체 용량은 약 34,160KB (차이가 생존자 공간, 그 적은 부분 두개로 나눠서 마크 카피하던거)
* gc 호출 시점이 함수 내부라서 그렇다 (로컬인 List<OOMObject> 객체가 살아있어서). 메소드 밖으로 빼면 "범위 안"에 존재하는게 아니라, 회수된다 (범위란??)


* Thread 탭은 위에서 jstack 으로 스레드 덤프의 UI 와 같다. 위처럼 RUNNABLE 상태인지, WAITING 상태인지, 혹은 교착상태인지도 확인할 수 있다
3. VisualVM
* 일반적인 운영 및 대응, 성능 분석 등을 제공하는 자바 문제 해결 도구. agent sw 없이 활용할 수 있고, 운영 환경에서 바로 실행 가능
>> jps, jinfo, jstat, jstack 기능, map, jhat 기능 지원 (플러그인으로 갖추고 있음)
>> 메서드 수준에서 가장 빈번히 호출되고 긴 시간을 소모하는 메소드 확인 가능
>> 덤프나 런타임 설정 등을 스냅샷하여 전송가능
* 원하는 애플리케이션에 대한 힙 덤프 생성이 가능하고, Summary (앱 시스템 속성 조회), Objects, Threads, OQL Console 등 다양한 항목을 지원한다.
* Profiler 항목을 통해서 프로그램이 동작하는 도중 CPU 사용 시간과 메모리 사용량을 메소드 수준에서 분석 가능
>> 단, 해당 기능은 런타임 성능에 영향을 주기 때문에 운영에서 직접 사용하지는 않음 (JMC 란건 부담이 적어서, 이걸 자주 쓴다고 함)
* BTrace 는 원래 코드에 없던 디버깅용 코드를 동적으로 삽입할 수 있는 도구, 보통 필요한 로그가 없던 상황이면 재배포를 해야함
// 대충 엔텉 키를 누를 떄마다 1000 이하의 무작위 정수 두 개를 생성하고 더한 값을 출력하는 작업을 반복하는 코드
>> 이 때 생성된 정수가 어떤 것들인지 로깅되어야 한다는 요구 사항 추가
@BTrace
public class TracingScript {
@OnMethod( // BTrace 로 추가하는 기능인 듯
clazz="org.fenixsoft.jvm.chapter4.BtraceTest"
method="add",
location=@Location(Kind.RETURN)
)
public static void func(@Self org.fenixsoft.jvm.chapter4.BTraceTest instance
, int a, int b, @Return int result) { // 반환 값이 뭔지 캐치하는 듯
println("콜 스택");
jstack();
println("메서드 매개 변수 A:", str(a));
println("메서드 매개 변수 B:", str(b));
println("메서드 결과:", str(result));
}
}
>> BTrace 기능을 사용하면 IDE 같은 탭이 포함되어 있는데, 다음과 같이 디버깅 코드를 작성 후 돌리면, 원할 때마다 Outptut 패널에 추가한 로그가 출력된다
<사진?
* BTrace 는 콜 스택, 매개 변수, 반환값 출력은 기본적인 쓰임이고, 성능 모니터링, 연결 누수 / 메모리 누수 찾기, 스레드 경합 해결 등에서 모두 활용 가능
4. JMC
* 오라클 유료 지원 서비스 중에는 AMC, JUT, JFR, JMC 등이 있고, 이 중 JMC 는 자바 가상 머신 모니터링 시스템이다. 유료 라이센스지만, 개인은 무료.
* 이클립스 느낌이 나는 JMC 는 따로 다운로드가 가능하며, 자동으로 가상 머신 목록들을 조회 후 Connection 으로 연결이 가능하다 (JMC는 MBean 과 JFR을 데이터 소스로 함, JFR은 첫 등장인듯)
* 어느 정도 레코드를 할지 시간 설정이 가능하며, GC, 컴파일러, 메서드 프로파일링 방법, 예외 기록 수준, 파일 및 소켓IO 등에 대한 레코드 옵션 및 빈도 설정도 가능
* 그리고 나온 보고서는 다음과 같은 내용을 담고 있다
>> 애플리케이션: 앱이 쓴 스레드, 락, 메모리, 파일및 소켓IO, 메서드별 정보, 발생한 예외, 스레드 덤프 등
>> JVM 내부 정보: GC, JIT 컴파일 정보 등
>> 환경: JVM이 실행 중인 프로세스, 환경 변수 등
>> 이벤트: Event type 관련 정보?

* JFR은 MBean 보다 얻을 수 있는 데이터의 수준이 훨씬 높고, 프로세스 성능에 큰 영향을 주지 않음. JMC를 그래서 운영 프로덕션에는 더 활용할만 하다고 보는 듯
핫스팟 가상 머신 플러그인과 도구
1. HSDIS
* <JVM 명세서> 에는 JVM 세트에 속한 명령어들이 정의되어 있음. 이는 점점 개념 모델이 되어 갔고 (초반에 역사에서 많이 살펴본 부분인 듯), 이를 실행하는 구현체들은 더 다양해졌다
>> "프로그램 실행의 의미"를 논할때는 바이트 코드 분석이 핑요하지만, "동작 (어떻게 동작하고 성능은 어떤지)"을 논할 때는 바이트 코드는 무의미 (??)
>> 보통 프로그램 동작 분석은 디버깅 도구로 중단점을 설정해 가며 수행, 하지만 JIT 컴파일러 등으로 많은 문제 -> HSDIS 의 등장
* HSDIS 는 JIT 컴파일 코드용 디스어셈블리 플러그인 (핫스팟 VM 변수로 -XX:+PrintAssembly 로 가능) -> JIT 컴파일러가 동적으로 생성한 네이티브 코드를 HSDIS 가 어셈블리 코드로 복원해 출력
* 책에 예시가 있으니 살펴봐도 좋음
2. JIT WATCH
* JIT 컴파일러용 로그 분석 및 시각화 도구, 매개변수로 로그 설정 및 JITWatch 가 읽어들일 로그를 저장해 주는 방식으로 진행
* 로그 파일을 읽어오면 자바 소스 코드, 바이트코드, JIT 컴파일러가 생성한 어셈블리 코드 등을 동시에 확인할 수 있다
