JIT Watch를 사용하면 핫스팟이 실제로 런타임에 바이트 코드에 무슨 일을 했는지 보여주는 도구라고 한다.
JIT는 프로파일 기반의 최적화를 사용해 JIT 컴파일 여부를 판단함.
인터프리터와 C1 컴파일러는 JIT 컴파일러가 언제, 무슨 최적화를 할지 결정하는데 필요한 정보를 Method Data Object에 기록
해둔다.
인라이닝
JIT는 인라이닝 기능을 제공하는데, 쉽게 얘기해서 함수를 호출하지 않고 함수의 내용을 그대로 호출부쪽으로 옮겨오는 기능이다. ( 코틀린에서는 inline이라는 키워드로 이것을 제공함 )
루프 펼치기
루프 내부의 메소드 호출을 전부 인라이닝 하면 루프 한 번 순회마다 얼마의 비용이 드는지, 반복되는 코드의 크기 등을 분석하기가 용이해짐.
이 정보를 토대로 매번 순회시 루프 처음으로 되돌아가는 횟수를 줄이기 위해 루프를 펼쳐서 최적화 한다.
이 짓을 항상 하는 건 아니고, 아키텍처, 핫스팟 버전에 따라 다름
탈출 분석
메서드 내부에서 할당된 객체를 메서드 범위 밖에서 바라볼 수 있는지를 알아보는 용도로 쓰임.
주로 객체가 메서드를 탈출하지 않으면, (NoEscape) VM은 객체 필드를 처음부터 객체 필드가 아닌 지역 변수였던 것 처럼 변환함.
결국 탈출 분석의 목표는 해당 객체의 힙 할당을 막음으로써 GC를 조금 더 덜 발생시키자는 취지로 보임.
단형성 디스패치
어떤 객체의 메서드를 호출할 때, 그 메서드를 최초로 호출한 객체의 런타임 타입을 알아내면 그 이후의 모든 호출도 동일한 타입일 가능성이 크다는 전제를 기반으로 한 최적화.
결국 이 추측을 토대로 JVM 내부에서 해당 객체 자체를 캐싱해서 klass 포인터나 vtable을 통해 가상 룩업 하는 일을 한 번만 수행하고자 하는 것이 목표. (최초에 호출한 클래스 이후에 모든 클래스가 같다면, 그 instanceOOP는 같은 klass 포인터를 바라보고 있을테니까)
인트린직
JIT 서브시스템이 동적 생성하기 이전, JVM이 이미 알고 있는, 고도로 튜닝된 네이티브 메서드 구현체를 가르키는 용어.
네이티브 메서드라고 하니까 왠지 C나 C++로 개발되어있을 것 같은 느낌.
온-스택 치환
컴파일을 할 정도로 호출 빈도가 높지는 않지만, 메서드 내부에 핫 루프가 포함된 경우.
핫 루프가 무슨 뜻일까 생각해봤는데, 에제를 봤을 때는 횟수가 많은 루프문을 의미하는 것 같음.
이럴 경우 한계치를 초과하면 OSR(온스택치환)을 사용해 루프를 컴파일한 후 치환해서 실행한다고 함.
그 외
메서드를 작게 유지하면 인라이닝 가짓수가 늘어난다.
JIT가 최적화할 여지를 주는 것이므로 메서드를 가급적 작게 유지하면 좋을 듯. ( 읽기도 좋고 )
실제로 메서드 바이트 코드 크기로 분석한 자료를 보면, 8000바이트 이하일 때와 8000바이트 이상일 대의 성능이 2배가까이 차이가 남을 알 수 있음.
JIT
인라이닝
루프 펼치기
탈출 분석
단형성 디스패치
인트린직
온-스택 치환
그 외
GraalVM 관련