JVM
JVM이란
java virtual machine
java는 OS에 종속적이지 않습니다. 그래서 os위에서 java를 실행하기 위해선 무언가가 필요한데,
자바를 인식하고 실행하게 해주는 가상 컴퓨터가 바로 JVM입니다.
java 소스코드(.java 파일)는 CPU가 인식할 수 없어 기계어로 컴파일이 필요합니다.
여기서 java compiler를 통해서 Java bytecode(.class파일)로 변환을 먼저 합니다.
java compiler는 jdk를 설치하면 bin에 존재하는 javac.exe를 의미합니다.
그래서 javac 명령어를 통해 .class파일로 컴파일이 가능하다.
javac 파일명.java
하지만 bytecode도 아직 기계어는 아닙니다. 그래서 이때 JVM이 OS가 bytecode를 이해할 수 있도록 해석해준다.
그래서 bytecode는 jvm 위에서 os 상관없이 실행할 수 있습니다.
java 파일명
이 명령어를 통해서 파일이 실행된 것을 확인할 수 있습니다.
bytecode란?
vm에서 돌아가는 실행프로그램을 위한 이진표현법
java bytecode는 jvm이 이해할 수 있는 언어로 변환된 자바 소스코드를 의미합니다.
이 코드는 다시 실시간 번역기 또는 JIT컴파일러에 의해 바이너리 코드로 변환됩니다.
(0과 1로 이루어진 코드, 컴퓨터가 인식할 수 있다.)
JIT 컴파일러란?
JIT 컴파일(just-in-time compliation) 또는 동적 번역(dynamic translation) 이라고 합니다.
인터프리터 방식의 단점을 보완하기 위해 도입되었다.(단점찾기)
인터프리터 방식이 항상 단점인 것은 아닙니다!
JIT 컴파일러가 컴파일하는 과정은 바이트 코드를 인터프리팅하는 것보다 훨씬 오래걸리므로 한 번만 실행되는 코드라면 컴파일 하지 않고 인터프리팅하는 것이 유리할 수도 있습니다.
JVM 실행 과정,구성 요소
클래스 로더(Class Loader)
실행 엔진(Execution Engine)
인터프리터(Interpreter)
JIT 컴파일러(Just-in-Time)
가비지 콜렉터(Garbage collector)
런타임 데이터 영역 (Runtime Data Area)
실행 과정
1. 어플리케이션이 실행되면 JVM은 OS로부터 메모리를 할당받는다.
JVM은 할당 받은 메모리를 용도에 따라 영역을 구분해서 관리한다.
2. 자바 컴파일러는(javac.exe)가 자바 소스코드(.java)를 읽어 bytecode(.class)로 변환한다.
3. Class loader를 통해 바이트코드를 JVM으로 로딩한다.
4. 로딩된 바이트코드는 실행 엔진을 통해 실행된다.(실행되는 과정에서 GC같은 작업이 실행된다.
클래스 로더
JVM 내로 클래스 파일(.class)을 로드하고, 링크를 통해 배치하는 작업을 수행하는 모듈이다.
로드된 바이트 코드를 묶어 JVM의 메모리 영역인 Runtime Data Areas에 배치한다.
클래스를 메모리에 올리는 로딩 기능은 한번에 메모리에 올리지 않고, 어플리케이션에서 필요한 경우 동적으로 메모리에 적재한다.
클래스 파일의 로딩은 3단계로 구성이 된다. (Loading - > linking -> initialization)
실행 엔진
바이트코드를(.class를) 실행시키는 역할
자세히 설명하자면, 클래스 로더가 JVM내의 런타임 데이터 영역에 바이트 코드를 배치시키고, 이것은 실행 엔진으로 실행한다.(바이트 코드를 기계가 실행할 수 있는 형태로 변경하기 위해서)
코드를 실행하는 방식은 2가지 방식이 있습니다.
1. 인터프리터
바이트 코드를 해석해서 실행하는 역할
(다만 같은 메소드여도 여러번 호출되면 매번 새로 수행해야 한다.)
하지만 한 줄씩 수행하기 때문에 느리다는 단점이 있다.
2. JIT(Just-In-Time) Compiler
인터프리터의 단점을 해소하는 역할
반복되는 코드를 발견해 전체 바이트 코드를 컴파일하고 그것을 Native code(자바에서 부모가 되는 C,C++,어셈블리어)로 변경해서 사용한다.
3. 가비지 콜렉터 자세히
더이상 사용되지 않는 인스턴스를 찾아 메모리에서 삭제하는 역할 (new로 클래스 객체. String 객체)
일반적으로 자동으로 실행되며, 수동으로 실행할 경우에는 System.gc()를 사용할 수 있다. (실행이 보장되지는 않는다.)
Garbage : 앞으로 사용되지 않는 객체의 메모리
GC : 이를 스케줄에 의해 정리해주는 것
Stop The World
gc를 위해 jvm이 멈추는 현상 gc가 작동하는 동안 gc관련 스레드를 제외한 모든 스레드는 멈추고
튜닝은 이 시간을 최소화하는 것을 의미 ( ex performance 튜닝)
CNS gc, Parallel gc(java 8), G1 gc (java 9,10), Z gc(11) : 서비스 특성에 맞는 GC가 있음
Runtime Data Area
어플리케이션이 동작하기 위해 OS에서 할당받은 메모리 공간
os로 부터 메모리를 할당받고 해당 메로리를 용도에 따라 여러 영역으로 나누어 관리한다.
PC Register
PC : Program Counter
Thread가 시작될 때 생성되는 공간으로, 현재 실행중인 상태 정보(Stack frame의 주소)를 저장하는 영역
스레드 생성시마다 하나씩 존재한다.
스레드가 로직을 처리하면서 지속적으로 갱신 된다.
Thread가 어떤 부분을 어떤 명령으로 실행해야할 지에 대한 기록을 하는 부분으로 현재 수행 중인 JVM 명령의 주소를 갖는다.
JVM stack area
메서드 호출을 Stack frame이라는 블록으로 쌓으며 로컬 변수, 중간 연산 결과들을 stack area에 생성 및 저장해 두었다가 메소드를 빠져나가면 바로 소멸되는 특성의 데이터를 저장하기 위한 영역이다.
바로 소멸되는 특성의 데이터를 저장한다. 스레드 역할이 종료되면 프레임 별로 삭제한다.
각종 형태의 변수나 임시 데이터, 스레드 또는 메소드 정보(매개변수, 지역변수, 리턴 값 및 연산 시 일어나는 값)를 저장한다.
Native method stack
자바 프로그램이 컴파일되어 생성되는 바이트 코드가 아닌 실제 실행할 수 있는 기계어로 작성된 프로그램을 실행시키는 영역.
JAVA가 아닌 c/c++의 로우 레벨 코드를 실행하기 위한 공간.
Java Native Interface를 통해 바이트 코드로 전환하여 저장하게 된다.
각 스레드 별로 생성된다.
JNI(Java Native Interface)
자바가 다른 언어(C,C++)로 만들어진 어플리케이션과 상호 작용할 수 있는 인터페이스를 제공한다.
JVM이 Native 메소드를 적재하고 수행할 수 있도록 한다.
Heap Area (Java 8)
모든 스레드가 공유하는 영역
어플리케이션이 실행 중에 생성되는 객체 인스턴스를 저장하는 영역 -> gc에 의해 관리되는 영역
new 연산자로 생성된 모든 Object와 Instance 변수, 그리고 배열을 저장
1. Young Generation
생명 주기가 짧은 객체를 GC 대상으로 하는 영역
Eden에 할당 후 Survivor 0과 1을 거쳐 오래 사용되는 객체를 Old generation으로 이동시킨다.
2. Old Generation
생명 주기가 긴 객체를 GC 대상으로 하는 영역
GC 생명주기에 의해 지속적으로 메모리가 정리된다.
Method Area (= Class Area = Static area)
모든 스레드가 공유하는 영역
프로그램의 클래스 구조를 메타데이터(구조화된 데이터)처럼 가지며 메소드의 코드를 저장한다.
static으로 선언된 변수들을 포함하여 Class 레벨의 모든 데이터가 이곳에 저장된다.
JVM마다 단 하나의 Method Area가 존재하는데 이 안에서도 Runtime Constant Pool이라는 별도의 영역이 존재한다.
저장되는 정보의 종류
Field info : 멤버 변수의 이름, 데이터 타입, 접근 제어자의 정보
Method info : 메소드 이름, return 타입, 매개변수, 접근 제어자의 정보
Type info : Class 인지, Interface인지 여부를 저장, Type의 속성, 이름, Super Class의 이름
Heap처럼 GC 관리 대상이다.
Method area와 Heap area는 여러 스레드들 간에 공유되는 메모리(멀티 스레딩)
Runtime Constant Pool
static 영역에 존재하는 별도의 관리영역.
상수 자료형을 저장하여 참조하고 중복을 막는 역할을 수행한다.
JVM의 Root Space를 파악하기
확인해야 하는 요소
1. JVM메모리의 stack의 로컬 변수
2. method area에 저장된 static 변수
3. native method stack에 작성된 JNI참조