[자바 최적화] JVM이야기
자바 최적화 책 정리
자바 최적화(Optimizing Java) | 벤저민 J. 에번스 - 교보문고
자바 최적화(Optimizing Java) | 자바 애플리케이션 성능을 한 단계 높여줄 튜닝 이야기성능 튜닝은 실험과학이다. 추측과 구전 튜닝에 의존할 일이 아니다. 이 책은 복잡한 기술 스택을 다루는 중/고
product.kyobobook.co.kr
인터프리팅과 클래스로딩
✅ 인터프리팅
JVM은 스택 기반의 해석 머신이다.
-> 어떤 메서드의 호출 스택, 혹은 일부 결과를 스택에 보관하며, 이 스택의 맨 위에 쌓인 값들을 가져와 계산한다.
-> 인터프리터는 스택의 위에서부터 옵코드(명령)를 하나씩 순서대로 처리하는 'while 루프 안의 switch문'이다.
✅ 클래스로딩
JVM이 클래스 파일을 실행하기 위해 클래스를 메모리에 로딩한다.
<부트스트랩 클래스로더>
자바 런타임 코어 클래스(다른 클래스로더가 필요한 클래스를 로더할 수 있게 하는 최소한의 필수 클래스 -> Object, Class, Classloader...)를 로드한다.
- Java 8: rt.jar 파일에서 가져온다.
- Java 9: 런타임이 모듈화됨에 따라 rt.jar 파일이 없어지고 그 내용들은 모듈 시스템에 맞게 효율적으로 재편되었다.
따라서, 부트스트랩 클래스로더가 로딩할 수 있는 클래스의 범위는 ClassLoader 아래 최상위 클래스들 정도로 줄어들었다.
<확장 클래스로더>
부트스트랩 클래스로더를 부모로 설정하고, 필요할 때 클래스로딩 작업을 부모에게 넘긴다.
특정한 OS나 플랫폼에 네이티브 코드(OS에서 직접 컴파일하여 기계어로 실행 가능한 코드 -> C/C++, ...)를 제공하거나 기본 환경을 오버라이드 할 수 있다.
ex) Nashorn
확장 클래스로더가 로드하는, Java 8 버전 부터 나온 JVM의 공식 JavaScript 엔진.
런타임 동안 JavaScript를 Java 바이트 코드로 컴파일하기 때문에, Java와 JavaScript의 사이의 높은 상호 운용성을 제공한다.
- Java 8: jre/lib/ext 폴더 등에서 클래스 파일을 가져온다.
- Java 9: jre/lib/ext 폴더가 없어지고, Java SE의 모든 클래스를 볼 수 있어서, Java 8에 비해 범위가 확장되었다.
<애플리케이션 클래스로더>
확장 클래스로더를 부모로 설정하고,
지정된 클래스패스에 위치한 유저 클래스를 로드한다.
<동작 원리>
1. 자바 프로그램 실행 중 처음 보는 새 클래스를 애플리케이션 클래스로더에 요청한다.
2. 만약 클래스로더에서 클래스를 찾지 못하면 자신의 부모 클래스로더에 위임한다.
3. 이렇게 부모의 부모로 거슬러 올라가 결국 부트스트랩도 해당 클래스를 찾지 못하면 ClassNotFoundException 예외가 발생한다.
-> 나중에 뒤탈을 없애려면 빌드 프로세스 수립 시, 운영 환경과 동일한 클래스패스로 컴파일하는 것이 좋겠다.
+) 클래스는 (패키지 명을 포함한) 풀 클래스명과 자신을 로드한 클래스로더, 두 가지 정보로 식별된다.
바이트코드 실행
✅ 자바 컴파일러
자바 소스 코드는 실행되기까지 많은 변환 과정을 거치는데,
그 첫 단계는 자바 컴파일러(javac)를 이용해 컴파일 하는 것으로,
자바 소스 코드를 바이트코드로 구성된 .class 파일로 바꾸는 것이다.
✅ 바이트코드
바이트코드는 특정 컴퓨터 아키텍처에 지배를 받지 않고,
JVM 지원 플랫폼 어디서건 실행할 수 있다.
-> 이식성이 좋다고 할 수 있다.
클래스 파일은 VM 명세서에 정의된 구조를 따른다.
컴포넌트 | 설명 | 참고 |
매직 넘버 | 0xCAFEBABE | 이 파일이 클래스 파일임을 나타내는 4바이트 16진수 자바 9부터는 0xCAFEDADA |
클래스 파일 포맷 버전 | 클래스 파일의 메이저/마이너 버전 | 클래스를 실행하는 JVM이 컴파일한 JVM보다 버전이 낮으면 UnsupportedClassVersionError 발생 |
상수 풀 | 클래스 상수들이 모여 있는 위치 | 코드 곳곳에 등장하는 상숫값 (클래스명, 인터페이스명, 필드명, ...) |
액세스 플래그 | 추상 클래스, 정적 클래스 등 클래스 종류를 표시 | |
this 클래스 | 현재 클래스명 | 상수 풀을 가리키는 인덱스로 표시 |
슈퍼클래스 | 슈퍼클래스(부모클래스)명 | |
인터페이스 | 클래스가 구현한 모든 인터페이스 | |
필드 | 클래스에 들어 있는 모든 필드 | |
메서드 | 클래스에 들어 있는 모든 메서드 | |
속성 | 클래스에 들어 있는 모든 속성 (ex. 소스 파일명 등) |
핫스팟 입문
✅ 핫스팟
1999년 썬 마이크로시스템즈에서 핫스팟 VM을 선보이고,
자바는 C/C++ 같은 언어에 필적할 만한 성능을 자랑하며 진화를 거듭했다.
✅ 제로 코스트 vs 개발자의 생산성
언어 및 플랫폼 설계는 추구하는 바를 끊임없이 저울질하며 결정을 내려야 할 일이 따른다.
ex)
1. 제로 코스트 추상화 사상에 근거한 '기계에 가까운 언어' -> C/C++
2. 개발자의 생산성을 위해 저수준 제어라는 일을 대행하는 언어 -> Java
-> 자바는 후자로서, 런타임 동작을 분석하고 성능에 가장 유리한 방향으로 영리한 최적화를 적용한다.
✅ 핫스팟 VM의 목표
개발자가 제로 코스트를 위해 억지로 VM 틀에 맞게 프로그램을 욱여넣는 대신,
자연스럽게 자바 코드를 작성하고 바람직한 설계 원리를 따르도록 한다.
JIT 컴파일이란?
✅ JIT 컴파일
바이트코드는 여러 플랫폼에서 클래스 파일을 문제 없이 실행할 수 있지만,
프로그램이 성능을 최대로 내려면 네이티브 기능을 활용해 CPU에서 직접 프로그램을 실행시켜야 한다.
핫스팟은 인터프리티드 모드로 실행하는 동안, 애플리케이션을 모니터링하면서,
가장 자주 실행되는 코드 파트를 발견해 JIT(Just-In-Time, 그때그때 하는) 컴파일을 수행한다.
✅ JIT 컴파일 장점
1. 프로필 기반 최적화(PGO): 컴파일러가 실제 프로그램을 실행하며 수집한 추적 정보를 근거로 최적화를 결정한다.
-> 상황별로 수집한 정보를 토대로 핫스팟이 더 올바른 방향으로 최적화할 수 있다.
2. 런타임 정보를 활용하기 때문에, 동적 인라이닝, 가상 호출 등으로 성능을 개선할 수 있다.
JVM 메모리 관리
✅ 가비지 수집(Garbage Collection)
핫스팟의 컴파일 시스템과 더불어 자바를 독보적인 언어로 만들었던 특징.
힙 메모리에 대해 불필요한 메모리를 회수하거나 재사용하는 프로세스.
스레딩과 자바 메모리 모델(JMM)
✅ 멀티스레딩
자바는 1.0부터 멀티스레드 프로그래밍을 기본 지원했다.
-> 보통 주류의 JVM 구현체에서는 자바 애플리케이션 스레드는 각각 정확히 하나의 전용 OS 스레드에 대응된다.
1990년대 후반부터 자바의 멀티스레드 방식은 다음 세 가지 기본 설계 원칙에 기반한다.
- 자바 프로세스의 모든 스레드는 가비지가 수집되는 하나의 공용 힙을 가진다.
- 한 스레드가 생성한 객체는 그 객체를 참조하는 다른 스레드가 액세스할 수 있다.
- 기본적으로 객체는 변경가능하다.
✅ JMM
서로 다른 실행 스레드가 객체 안에 변경되는 값을 어떻게 바라보는지를 기술한 공식 메모리 모델이다.
ex)
스레드 A와 스레드 B가 둘 다 같은 객체를 참조할 때,
스레드 A가 객체의 값을 바꾸면 스레드 B는 무슨 값을 참조하게 될까?
-> 복잡한 문제이기에, 이후 책(3장, 12장)에서 관련 내용을 다룬다.
JVM 구현체 종류
오라클이 제작한 핫스팟 이외에도 제각기 다른 방법으로 구현한 자바 구현체가 많다.
✅ OpenJDK
오라클이 주관하며, 자바 기준 구현체(다른 개발자가 참조할 수 있는 샘플 프로그램)를 제공하는 특별한 오픈소스 프로젝트다.
GPL 라이선스(소프트웨어의 실행, 연구, 공유, 수정의 자유를 사용자에게 보장)를 갖고 있다.
✅ 오라클 자바(Oracle)
OpenJDK 기반이지만, 오라클 상용 라이선스로 재라이선스를 받았다.
오라클 자바에 변경된 내용은 거의 전부 OpenJDK 공개 저장소에 커밋된다.
✅ 줄루(Zulu)
아줄 시스템이 제작한, 자바 풀 인증(GPL)을 받은 OpenJDK 구현체다.
✅ 아이스티(IcedTea)
래드햇이 제작한, 자바 풀 인증을 받은 OpenJDK 구현체다.
✅ 징(Zing)
아줄 시스템이 제작한, 자바 풀 인증을 받은 고성능 상용 JVM이다.
✅ J9
IBM이 제작했고, 지금은 이클립스 OMR 프로젝트 기반으로 제작되며, IBM 상용 제품의 근간을 이루고 있다.
✅ 애비안(Avian)
자바 풀 인증을 받은 구현체가 아니라, 제품으로 쓰기에 완벽한 솔루션은 아니다.
그러나 JVM의 세부 작동 원리가 궁금한 개발자에게 훌륭한 학습 도구 역할을 한다.
✅ 안드로이드(Android)
이 책은 핫스팟에 관한 내용이 대부분이고, 이는 오라클 자바, 아줄 줄루, 래드햇 아이스티 등 OpenJDK에서 파생된 JVM에 똑같이 적용된다. 다만, 안드로이드 기술 스택은 다소 거리가 있으므로 책에서 안드로이드는 고려 대상에서 제외한다.
JVM 라이선스
JVM 구현체는 거의 다 오픈소스이고,
IBM J9, 아줄 징을 제외하면 대부분 핫스팟(GPL 라이선스)에서 비롯된 제품이다.
그런데 오라클 자바는 OpenJDK 코드 베이스지만 오픈 소스가 아닌 상용 제품이고,
오라클 JDK와 OpenJDK는 라이선스 외에는 아무런 차이가 없다.
JVM 모니터링과 툴링
✅ 모니터링
JVM은 실행 중인 애플리케이션을 인스트루먼테이션(오류 진단이나 성능 개선을 위해 애플리케이션에 특정한 코드를 끼워 넣는 것), 모니터링 등 다양한 기술을 제공한다.
<자바 관리 확장(JMX)>
JVM과 그 위에서 동작하는 애플리케이션을 제어하고 모니터링하는 강력한 범용 툴이다.
<자바 에이전트>
자바 언어로 작성된 툴 컴포넌트로, java.lang.instrument 인터페이스로 바이트코드를 조작한다.
<JVM 툴 인터페이스(JVMTI)>
JVM의 네이티브 인터페이스로, 네이티브 컴파일 언어로 작성해야 한다.
JVM 이벤트를 모니터링하며 알림을 받을 수 있도록 하는 통신 인터페이스다.
-> 네이티브이기 때문에 아무래도 자바 에이전트를 사용하는 것이 났다.
<서비서빌리티 에이전트(SA)>
자바 객체, 핫스팟 자료 구조 모두 표출 가능한 API와 툴을 모아놓은 것.
JVM 진단, 모니터링 등의 작업을 위해 사용되는 도구.
VisualVM
넷빈즈 플랫폼 기반의 시각화 툴
참고자료
https://dzone.com/articles/the-magic-word-in-java-cafebabe
https://blog.lse.epita.fr//2014/04/28/0xcafebabe-java-class-file-format-an-overview.html