JVM

JVM 이란?

Java Virtual Machine


Goal

  • JVM의 개념에 대해서 알아봅니다.
  • JVM의 내부는 어떻게 이루어져있는지 알아봅니다.
  • Java7과 Java8에서 JVM에 어떤 변화가 있었는지 간략하게 알아봅니다.

What

JVM이란 자바프로그램이 어느 기기나 운영체제에서도 실행될 수 있게 해주는 머신을 이야기합니다.

  • JVM 은 JAVA와 OS사이에서 중개자 역할을 수행해, OS에 구애받지 않고 자바 코드를 수행할 수 있게해줍니다.
  • 또한 메모리를 관리하고, GC를 수행해줍니다.

자바 프로그램 실행과정

image

  1. JVM은 OS로부터 프로그램이 필요로 하는 메모리를 할당 받습니다.
  2. 자바컴파일러인 javac가 자바 코드를 읽어드려 바이트코드(class)로 변환시킵니다.
  3. 클래스 로더를 통해 class파일들을 JVM으로 Loading 합니다.
  4. Loading된 class 파일들은 Execution 엔진을 통해 해석이 됩니다.
  5. 해석된 바이트 코드들은 Runtime Data Areas에 배치되어 실제 수행이 이루어집니다.
1
2
3
컴파일러 javac가 자바소스코드를 읽고 자바 바이트 코드로 변환합니다.
바이트 코드들을 클래스 로더를 통해 JVM 메모리 영역으로 로딩합니다.
로딩된 파일들은 엔진을 통해 해석되고 수행이 이루어집니다.

📌 JVM 구성

1. Class Loader

JVM 내부로 클래스 파일을 로드하는 모듈을 말합니다.

  • 런타임시에 클래스를 적재하고, 올바른 바이트코드로 작성되었는지 검사합니다.

2. Execution Engine(실행 엔진)

클래스(.class)를 실행시키는 역할을 수행합니다.

  • JVM내부에 배치된 바이트 코드들을 실행 합니다.
  • .class 형태의 바이트 코드들은 사람이 읽기에는 편하나, 기계가 읽기는 불편한 형태이므로 기계어로 변경하여 실행합니다.
  • 인터프리터, JIT, GC가 이안에 속합니다.

2.1 Interpreter(인터프리터)

자바 바이트 코드를 명령어 단위로 읽어서 실행합니다.

  • 자바의 경우 인터프리터 + 컴파일러가 혼합된 언어입니다.
  • 하지만 한줄씩 읽기때문에 엄청 느리다라는 단점이 있습니다.

2.2 JIT(Just In Time)

인터프리터의 느린속도라는 단점을 해결하기 위해 추가된 일종의 컴파일러 입니다.

  • 자바의 코드는 인터프리터로 실행하다가 적절한 타이밍에는 직접 네이티브 코드로 실행하는 방식으로 동작합니다.
  • 루프를돌거나, 자주 호출되는 메소드의 경우에는 JVM이 내부적으로 컴파일을 해서 처리합니다.
1
2
3
4
5
6
7
8
9
// 동작방식

int x;
int y;
methodCall();
methodCall();
methodCall();

 있을때 methodCall() 메소드는 반복적으로 등장하게 됩니다.
  1. JIT는 먼저 전체 소스코드를 확인하며 중복되는 부분이 어디가 있는지 확인을 해둡니다.
  2. 일단은 인터프리터 방식으로 읽다가 첫번째 methodCall()을 만나는순간 이후에 중복이 있는것을 캐치합니다.
  3. 이후 methodCall() 부분을 인터프리터로 처리하지않고, 캐싱된 결과로 처리합니다.

2.3 GC (Gargabe Collection)

gc를 수행하는 모듈입니다.

  • Execution 안에 속합니다.

📌 Runtime Data Area (JVM Memory)

image

PC Register

Thread가 어떤 부분을 어떤 명령으로 실행해야할지를 기록하는 영역입니다.

  • JVM 명령의 주소를 가지고 있습니다.
  • Thread별로 명령을 따로 기억해야 하므로, Thread가 시작될때 마다 생성되게 됩니다.

JVM Langauge Stacks (JVM Stack)

메소드 내부에서 잠시 살아있는 데이터들을 저장하는 영역입니다.

  • 임시데이터, 변수, 스레드, 메소드의 정보를 저장합니다.
  • 메소드 호출때마다 각각의 스택 프레임이 생성되고, 메서드 수행이 끝나면 순차적으로 제거됩니다.

Native Method Stack

JAVA가 아닌 다른 언어로 작성된 코드를 실행시키는 영역입니다.

  • 일반적인 메소드를 실행하는 도중에는, JVM Stack에 쌓이다가, 해당 메소드 내부에서 다른언어로 작성된 메소드가 있다면 해당 메소드는 해당 영역에 쌓이게 됩니다.

Method Area

클래스 정보를 처음 메모리에 올릴때 초기화 되는 대상을 저장하는 영역입니다.

The method area is created on virtual machine start-up. Although the method area is logically part of the heap, by oracle jvm spec docs

  • 논리적인 개념입니다.
  • 프로그램을 구성하는 바이트 코드가 올라가게 됩니다
  • 클래스와 메소드 메타 데이터가 올라가는 공간입니다.
  • Java7 까지는 클래스와 메서드 메타데이터들을 PermGen에 할당했지만, Java8 이후부터는 Native 영역으로 이동하여 Metaspace 영역에 할당되게 되었습니다.
  • 정적 메소드와 정적 변수가 올라가게 됩니다.
    • Java7까지는 PermGen에 할당했지만, Java8 이후부터는 permGen은 사이즈 제한으로 인한 문제로 인해 없어지고, MetaSpace가 등장하게 되었고 정적 메소드, 변수들은 Heap에 할당되게 되었습니다.

Java Heap

new로 생성되는 객체를 저장하는 공간입니다.

  • Java Heap 은 아래 그림처럼 {New / Young} , {Old} 부분으로 나뉩니다.

  • Java7 Permanent Java8 Metaspace 는 Java Heap 영역에 속하지 않습니다. :x:
  • Java7은 Permanent Heap, Java8은 Native Memory 영역에 속합니다.

Java7

Untitled 1

Java8

image

  • 기존까지의 Permanent 영역에는 Class의 Meta Data, Method의 MeteData, Static Object 변수, 상수, JVM JIT 관련 데이터 등이 저장되어 있었습니다.
  • Java8 부터는 해당영역을 MetaSpace로 명칭을 변경하고, JVM이 아닌 OS가 관리하도록 변경되어 기존까지 JVM에 의해서 크기가 강제되던 메모리 사이즈에 여유가 생기게 되었습니다.

Conclusion

  • JVM은 JAVA와 OS사이에서 중개자 역할을 수행해, OS에 구애받지 않고 자바 코드를 수행할 수 있게해주며, 메모리를 관리하는 머신을 이야기합니다.
  • JVM은 크게 Class Loader, Execution Engine, Runtime Data Area 으로 나누어져 있습니다.
  • Execution Engine는 Interpreter, JIT, GC 로 구성되어있습니다.
  • Runtime Data Area는 Thread 별로 분리되는 영역과, Thread간 에도 공유되는 영역으로 나뉩니다.
  • Java8 부터는 pemgen이 사라지고, metaspace로 대체되었습니다.

Reference