[CS] 자바 JVM 이란?
JVM 이란?
Java Virtual Machine 으로써, 자바를 실행하기 위한 가상머신 이다. 자바의 경우 어떤 OS 에서도 실행할 수 있는 이식성을 가지고있는데 그 이유가 JVM 때문이다.
자바로 프로그래밍을 하다보면 .java
파일로 만들어진다. 그러면 자바 컴파일러가 .java
파일을 .class
파일로 변환해준다. 그 다음에 JVM 이 .class
파일을 OS 가 이해할 수 있도록 해석해준다.
여기서 .class
는 Java Bytecode 라고 하는데 JVM 에 있는 JIT 컴파일러가 OS 가 이해할 수 있는 Binary Code 로 변환시켜 준다.
JVM 구성 요소
클래스 로더
- 로딩(Loading) :
.class
파일을 메소드 영역에 저장한다. 변수나 메소드 정보 및class
,interface
,enum
관련 여부 등을 Runtime Data Area 의 Method Area 에 저장한다. - 링크(Linking) :
.class
를 필요로 하는 메모리에 할당 및 클래스에 정의된 필드, 메소드, 인터페이스 나타내는 데이터 구조를 준비한다. - 초기화(Initialization) : 클래스 변수(static 필드)들을 적절한 값으로 초기화 한다.
실행 엔진
클래스 로더를 통해 Runtime Data Area 에 배치된 바이트코드를 읽어서 실행한다. 메모리에 적재된 클래스들을 기계어로 변경해 명령어 단위로 실행한다.
Interpreter
컴파일러와 같이 바이트코드를 기계어 변환해 준다는것은 동일하나 인터프리터는 소스코드의 각 행을 한줄 한줄 연속적으로 분석하며 실행해서 컴파일러에 비해 느리다.
JIT Compiler
Just In Time 컴파일러로 동적 번역이라고도 한다. 프로그램을 실제 실행하는 시점에 기계어로 번역한다. 인터프리터의 느린 단점을 보완하기 위해 도입되었다.
한번 컴파일한 코드(기계어)를 캐시에 보관해서 똑같은 코드를 만나면 빠른 수행이 가능하다. 하지만 컴파일하는 것도 시간이 드는것이므로 해당 코드가 얼마나 자주 수행하는지 확인하고 수행한다.
Garbage Collector
GC 라고 부르며 더 이상 사용도지 않는 인스턴스를 찾아 메모리에 삭제한다. 아래에 더 자세히 서술한다.
Runtime Data Area
PC Register
Thread 가 시작될 때 생성되며, Thread 하나당 한개씩 만들어진다. 현재 Thread 가 실행되는 부분의 주소와 명령을 저장한다.(CPU 의 PC Register 와 다른것이다)
JVM Stack
Thread 당 하나씩 Stack 영역을 가진다. 메소드가 호출될 시 할당되는 영역이다. 메소드의 지역변수, 파라미터 등이 할당된다. 여기서 할당은, Heap 공간에 객체 데이터를 올리고 그 객체 데이터에 대한 참조값이 할당된다. Heap 에 있는 객체가 Stack 에서 참조 할 수 없게되면 GC 의 대상이 된다.
Heap 에는 skills 객체의 데이터 0, 1, 2 그리고 name 객체의 데이터 kang 이 올라간다.
Stack 에는 skills, name, age 인 객체 데이터에 대한 참조값이 올라간다.
Native method stack
기계어로 작성된 프로그램을 실행시키는 영역이다. 자바가 아닌 다른언어로 작성된 네이티브 코드를 위한 메모리 영역이다.
Method Area
.class
를 클래스로더가 처음 메모리 공간(Runtime Data Area)에 올릴 때 저장되는 영역. 자바 프로그램의 클래스코드, 변수코드, static, final 변수 등이 있다.
Runtime Constant Pool
static 영역에 존재하는 별도의 관리영역
Heap Area
객체를 저장하는 가상메모리 공간. new
키워드로 생성한 객체가 저장되는 영역이다. 동적으로 생성된 객체와 배열이 저장되는 곳으로 GC 의 대상이 된다. Heap 영역은 3가지로 나뉜다.
- New/Young Generation : 생명주기가 짧은 젊은 객체들이 있다. Eden 은 객체들이 최초로 생성되는 공간, Survivor 는 Eden 에서 참조되는 객체들이 저장되는 공간이다. GC 대상이 되는 영영이다.
- Old Generation : 생명주기가 긴 오래된 객체들이 있다. New/Young Generation 에서 일정시간 참조되서 살아남은 객체들이 저장된다. GC 대상이 되는 영역이다.
- Permanent Generation : 생성된 객체들의 주소값, 메타 정보가 저장되는 영역이고 JVM 에 의해 사용된다. JDK 8 이후로는 사라진 영역이다. static 클래스와 상수가 해당 영역에 쌓이다 터저
OutOfMemory
문제를 해결하기 위해서 이다. JDK 8 이후로는 static 클래스와 상수는 힙 관리 영역에서 GC의 대상이 되도록 하고, 나머지는 Native Memory 영역으로 옮겨졌다. Native Memory 는 OS 에 의해서 관리된다.
Garbage Collector
힙 메모리 관리를 위해, 참조되고 있지 않는 객체들을 메모리에서 삭제한다. GC 가 스택의 모든 변수 또는 Reachable 객체를 스캔하면서 각각 어떤 객체를 참조하고 있는 찾는다(Mark) 이후 Mark 되어 있지 않는 객체들을 힙에서 제거한다.(Sweep)
Minor GC, Major GC
힙의 Young 영역에서 발생한 GC 를 Minor GC, Permanent 와 Old 에서 발생한 GC 를 Major GC 라고 한다.
GC 동작 과정
- 객체가 생성되면 힙의 Young 영역에 저장한다. 최초생성이면 Eden 영역에 저장한다.
- Eden 영역에서 Minor GC 가 발생하면, 참조 중인 객체는 1번 Survivor 영역으로 이동한다.
- 1번 Survivor 영역에서 Minor GC 가 발생하면, 참조 중인 객체는 2번 Survivor 영역으로 이동한다.
- Young 영역에서 오래 살아남은 객체는 Old 영역으로 이동한다.
- Old 영역에 있는 객체는 Major GC 가 발생했을 때, 참조 여부에 따라 유지되거나 제거된다.
GC 알고리즘 종류
- Serial GC : 싱글스레드로 동작하며 느리다. Mark-sweep-compact 알고리즘을 따른다. 적은 메모리와 CPU 코에 갯수가 적을 때 적합하다.
- Parallel GC : Java8 의 기본 GC, 작동알고리즘은 Serial GC 와 같지만 처리 Thread 가 여러개다. 메모리와 코어가 충분할 때 적합하다.
- Parallel Old GC : Parallel GC 는 Young 영역에만 Thread 를 사용하지만, 해당 GC 는 Old 영역까지 Thread 를 사용한다.
GC 장단점
장점
GC 알아서 Heap 메모리를 관리해주기 때문에 메모리 누수를 막을 수 있다.
단점
개발자가 GC 메모리 해제 타이밍을 정확히 모르기 때문에 실시간 프로그램의 경우 적합하지 않을 수 있다.
Reference
https://steady-coding.tistory.com/593
https://steady-coding.tistory.com/587
https://kotlinworld.com/3
https://devkingdom.tistory.com/226
https://doozi0316.tistory.com/entry/1%EC%A3%BC%EC%B0%A8-JVM%EC%9D%80-%EB%AC%B4%EC%97%87%EC%9D%B4%EB%A9%B0-%EC%9E%90%EB%B0%94-%EC%BD%94%EB%93%9C%EB%8A%94-%EC%96%B4%EB%96%BB%EA%B2%8C-%EC%8B%A4%ED%96%89%ED%95%98%EB%8A%94-%EA%B2%83%EC%9D%B8%EA%B0%80
https://thalals.tistory.com/314
https://jaehoney.tistory.com/177