유튜브 알고리즘이 추천해 줘서 보게 된 영상(JetBrains 채널 + 빡빡이 아저씨? 못 참지)
살면서 처음 듣는 러시아 영어라 알아듣기가 힘들었다.
그래서 부정확한 게 있을 수 있고, JVM에 대해 모르는 게 더 많기 때문에 제대로 알지 못하는 부분은 '?'를 붙여놓을 예정
목차
1. Intro
2. Java class file and bytecode
3. Classloading engine
4. Execution engine: interpretors, JIT, AOT
5. Meta information access subsystem: reflection, indy, JNI
6. Threading, exception handling, synchronization
7. Memory management: heap, allocation, GC
8. Managability and Monitoring
9. JVM Overview
1. Intro
연사 소개 (링크드인으로 대체)
https://www.linkedin.com/in/nikita-lipsky-04263920/
2. Java class file and bytecode
자바 프로그램을 JVM 상에서 구동하기 위해선, 자바 소스 파일(.java)을 javac 컴파일러를 통해 바이트 코드로 변환해야 함(.class파일)
Java class file
JVM 상에서 돌아가는 모든 프로그램은 진입점인 main 메소드와 classpath를 갖고 있음
main method
- 우리가 익히 아는 public static void main (String[] args)
classpath
- list of directories and archives (jar files)
- module path (since Java 9)
Java Runtime
JVM상에서 자바 프로그램을 실행하기 위해선 JRE(Java Runtime Environment) 또한 필요
JRE에 들어있는 것들
- JVM
- Platform classes
- core classes (java.lang.Object, java.lang.String, etc.)
- Java standard APIs (IO, NET, NIO, AWS/Swing, etc.)
- Implementation of native methods of platform classes
- OS specific, distributed as native dynamic labraries, .dll, .so, .dylib
- Auxiliary files (time zones, locales descriptions, media resources, etc.)
JVM
3. Classloading engine
JVM은 어떻게 클래스를 불러올까?
클래스 로딩의 대상이 되는 것들
- Java Runtime (platform classes)
- Application classpath
- Auto generated on-the-fly (Proxy, Reflection accessors, invoke dynamic implementation) (?)
- Provided by the application itself
모든 클래스는 classloader에 의해 load됨
- Platform classes are loaded by bootstrap class loader
- Classes from application classpath are loaded by the system class loader(AppClassLoader)
- Application classes may create user-defined class loaders
classloader는 각자 unique한 class namespace를 가짐 (?)
(namespace에는 클래스들을 FQCN(Fully Qualified Class Name으로 보관한다고 함 - 출처)
(그렇기 때문에 서로 다른 클래스를 동일한 FQCN으로 load할 수 있음 - 서로 다른 classloader를 사용하면 됨)
JVM Startup
main class가 system class loader에 의해 load됨(from application classpath or moduelpath)
- java.lang.Object와 같은 platform class와 이를 의존하는 것들을 load
public static void main (String[] args)를 실행
Class loading process (creation of class)
Class file parsing
- Class format이 정확한지 확인(ClassFormatError를 던질 수도 있음)
Creation of a runtime representation of the class in a special JVM memory area(Meta Space)
(Meta Space라는 곳에 class의 runtime 형태인 metadata를 생성)
- runtime constant pool in Method Area a.k.a Meta Space(After Java 8) a.k.a Permanent Generation(Before Java 8)
- (이 분 글에선 Meta Space의 경우 JVM이 아닌 native memory영역이라고 함)
Loading of a superclass and superinterfaces
Linking
자바 바이트 코드가 포함된 클래스 파일이 실행되기 전 linking 과정을 거침
Linking stage에서 일어나는 일
- Java bytecode verification
- 클래스 당 한번 수행됨
- Instructions correctness checks
- Operand stack and local variables out of bounds checks
- Type assign compatibility checks
- Preparation
- Resolution of symbolic references
- e.g. 클래스에서 다른 클래스를 참조하고 있다면, 이러한 정보를 연결
- symbolic reference들을 실제 값으로 바꿔줌
- 참고
Class initialization
static 블록과 static 멤버 변수의 값 할당
call of class static initializer
Happens on first use
- new
- static field access
- static method call
default method들을 통해 superclass, superinterfaces의 초기화 수행
(class initialization 부분은 따로 더 찾아봐야 할 것 같다.)
4. Execution engine: interpretors, JIT, AOT
JVM은 어떻게 Java bytecode를 실행할까?
Interpretation(Slow but portable)을 통해 실행하거나, native code로 바꾸어(Runs on the actual hardware) CPU에서 직접 실행되도록 한다.
Compilers
컴파일러를 최적화와 컴파일 수행 시점, 두 가지 측면에서 설명함
(영상에서 못 알아먹은 부분이나 모르는 부분은 다른 블로그(1번, 2번)를 참고해 추가했음)
Optimizing
- Non-optimizing
- Simple Optimizing
- HotSpot Client(C1)
- 빠르고 가벼움
- Sophisticated Optimizing
- HotSpot Server(C2)
- 높은 수준의 최적화
When they work
- JIT(Just-In-Time, Dynamic)
- 애플리케이션 런타임에 native code로 변환이 일어남
- 프로그램의 실행과 동시에(concurrently) 수행됨
- Compile hot(자주 수행되는) code only
출처 : GeeCON 2017: Nikita Lipsky - JIT vs. AOT: Unity And Conflict of Dynamic and Static Compilers (https://www.youtube.com/watch?v=CZVa4PBv2qg) - 왼쪽 아래의 profiler가 어떤 코드가 hot code인지 판단하고, 이를 JIT에 넘김
- AOT(Ahead-Of-Time, Static)
- 프로그램 실행 이전에 변환이 일어남
- 가장 공격적인 최적화 방법을 통해 프로그램의 모든 메소드를 컴파일
5. Meta information access subsystem: reflection, indy, JNI
Reflection
자바 프로그램에서 이름(string literal)을 통해 classes, fields, methods에 접근 가능하도록 해줌
Meta space 접근을 통해 JVM에서 reflection을 구현
JVM 기반의 프로그래밍 언어(Groovy, Clojure, Ruby, etc.)와 프레임워크(Spring) 구현을 위한 Java의 Key feature(주요 기능)
JNI(Java Native Interface)
JVM과 외부 세계(OS)를 묶어줌(bind)
C interface to the JVM
- JVM의 구현 디테일에 의존하지 않음
- C언어로 native method를 구현하는 데 사용
- IO, NET, AWT와 같이 Java SE API 중 플랫폼에 종속적인 API들을 구현하는 데 사용
Reflection과 마찬가지로 Meta space 접근을 통해 JVM에서 구현
6. Threading, exception handling, synchronization
java.lang.Thread
자바 thread는 native thread에 1대1로 매핑됨
각 thread는 stack을 가짐(지역 변수, thread 내에서 실행되는 method(method frame)들의 operand 스택을 포함함)
- JVM 옵션 -Xss을 통해 thread stack의 크기를 지정할 수 있음
자바 thread는 자기가 갖고 있는 stack에 대한 디테일한 정보들을 갖고 있음 (stack trace)
Project Loom
문제점 : native thread는 비싸다(cost가 높다). 얼마나 많은 native thread를 만들 수 있을까? 분명 제한이 있을 것
해결책 : Java 21부터 JVM이 관리하는 vitual threads(light-weighted threads)제공
Exception handling
JVM이 call stack에 대한 모든 걸 알고 있다는 사실이 exception handling을 구현하는 데 도움이 됨
Threads and Java Memory Model
thread를 사용하는 코드를 작성하는 건 쉬운 일이 아님(factos👀👀)
//영상 PPT 속 예제
// Thread 1:
Shared.data = getData();
Shared.ready = true;
// Thread 2:
...
while (!Shared.ready) {
// wait
}
data = Shared.data;
이렇게 코드를 작성했을 때 생길 수 있는 문제점은 무엇일까?
natvie code로 컴파일하는 과정 중 optimization(최적화) 과정에서 코드 순서가 바뀔 수 있음(reorder)
이 때문에 thread1의 Shared.data에 데이터가 할당되기 전에 ready 플래그가 true로 바뀌어 버린다면 thread2의 작업은 이상한 결과를 가져올 것
이를 해결하기 위해 ready 플래그를 volatile로 선언 > JVM이 reorder하지 않음
Synchronization
thread들 간에 공유된 memory(shared memory)에 안전하게 접근하기 위해 synchronized method나 synchronized block이 사용됨
naive하게 구현하면 OS에서 제공하는 synchronization primitive를 사용하게 됨(e.g. mutex, critical section, ...)
하지만 JVM이 항상 OS에서 제공하는 방법을 사용한다면 굉장히 느릴 것
(Java 프로그램에서 동기화는 굉장히 자주 일어나고, OS에서 제공하는 lock은 비용이 비싸기 때문)
오늘날에는 built-in synchronization 보다는 java.util.concurrent에서 제공하는 것들을 사용하기를 권장함
7. Memory management: heap, allocation, GC
Memory allocation
new 연산자의 구현
new를 통해 할당된 객체들은 Java heap에 위치
Must be fast
- JVM은 객체 하나에 대해서가 아닌, 여러 객체에 필요한 메모리를 한 번에 OS에 질의함
thread-safe하면서 parallel해야함(non-blocking)
Java Object Layout
layout이 JVM에 명시되어 있지 않음(JVM은 하나의 스펙일 뿐), 하지만 이렇게 하라라고 요구하는 것들이 있음
- Java Object header
- Reference to a class object
- Monitor(lock word)
- Identity hashcode
- GC flags
- Fields
- size 최적화, 정렬, 대상 아키텍처에 따라 재배열(reorder)될 수 있음
Garbage Collection
Garbage
프로그램에서 사용할 수 없는 객체들
GC roots
- 클래스의 static fields에 있는 객체들
- 쓰레드 내의 스택에서 접근 가능한 객체들
- native method에서 JNI 참조로 참조되는 객체들
Not garbage a.k.a live objects
- Objects from GC roots
- live objects에 의해 참조되는 객체들
그 외 모든 것들은 garbage임
Tracing garbage collectors
Mark-and-sweep
- GC roots부터 시작해서 live object들을 mark하고 garbage(not marked)들을 sweeps(free)
Stop-and-copy
- heap 공간을 2개의 공간으로 분할
- live object들을 두 번째 공간으로 복사
- 첫 번째 공간은 다음 collection 때 두 번째 공간으로 사용됨
Stop the world(STW)
live objects는 프로그램 실행 중 특정 시점에 정의됨(실행 과정에서 live object의 집합은 계속해서 변함)
GC를 위해선, garbage를 정의하기 위해 모든 쓰레드를 멈춰야 함(STW pause)
모던한 가비지 콜렉터들의 주요 task 중 하나는 STW pause를 줄이는 것.
STW pause를 줄이기 위한 방법
- Incremental
- GC pause 동안 모든 garbage를 collect하지 않음
- Parallel
- GC pause동안 쓰레드들을 병렬로 사용해 garbage collect
- Concurrent
- 프로그램 수행(execution)과 동시에 garbage collect
Generational Garbage Collection
Weak Generational Hypothesis
- Most objects die young
- old 객체들이 가끔 young 객체들을 참조
Generational GC
- incremental GC의 경우들 중 하나
- minor collection 사이클 동안, young 객체들만 추적됨
- 몇 사이클 동안 살아남은 객체들은 old generation으로 옮겨짐
Thread local Garbage Collection
Thread local Hypothesis
- 대부분의 객체들은 자신이 생성된 쓰레드에서 죽음
Thread local GC
- 다른 쓰레드를 멈추지 않고, 각 쓰레드 내에서 thread local garbage 수집
8. Managability and Monitoring
Manageability & Monitoring
JVM은 자바 프로그램에 대한 모든 걸 알고 있음
- load된 모든 클래스들
- 모든 live objects
- 모든 쓰레드들
- 쓰레드 내에서 실행된 모든 메소드들
JVM Tool Interface(JVM TI)
- debuggers
- profilters
Java Management Beans
- real time monitoring tools
- JConsole, JMX console, AMC
- Visual VM
- Java Mission Control
9. JVM Overview
JVM implementations
Java SE 명세를 따름
- Oracle HotSpot (Open JDK)
- IBM J9 (Open J9)
- Oracle JRockit (RIP)
- Excelsior JET (RIP)
- Azul Zing (HotSpot 기반이지만 자체 GC와 LLVM 기반 JIT을 포함하고 있음)
- GraalVM (HotSpot 기반, Java로 구현한 JIT이 들어있음)
- Liberica (Bellsoft), Amazon, MS, SAP, RedHat, JetBrains runtime
후기
JVM에 대해 알아보려면 어떤 것들을 알아봐야 하는지 체계를 잡을 수 있는 영상이라고 생각함
실제로 보면서 '이건 뭐지?'하고 궁금한 것들은 검색해 보니 잘 정리해 둔 블로그들이 많았다.
영상 정리한 걸 계속해서 보면서, 궁금한 것들이나 모르는 것들을 검색하면서 공부해야겠다.
'Java' 카테고리의 다른 글
자바의 신 개정판 Vol.1 - 10장 (0) | 2022.11.25 |
---|---|
자바의 신 개정판 Vol.1 - 9장 (0) | 2022.11.25 |
자바의 신 개정판 Vol.1 - 4장 (0) | 2022.10.19 |