개요
JVM(Java Virtual Machine)은 자바를 실행하기 위한 가상의 컴퓨터이다. Java는 OS에 종속되고 싶지 않았다. Windows, Mac, Linux, Android 상관없이 컴파일 했을때에도 정상 동작하기를 원했다. 자바는 크로스 컴파일을 제공하기 위해 가상 기계위에서 동작한다. OS나 CPU등의 상관없이 동일한 JVM위에서 실행되면 똑같은 컴파일 결과를 반환하게 된다.
Write Once Run Anywhere를 가능하게 한것이 자바의 핵심 이념이자 JVM이 탄생하게 된 배경이다.
JVM Memory Layout

그림과 함께 각 역할과 수행과정을 설명해보겠다.
- Java Compiler는 Java Source를 Byte Code로 컴파일한다.
- JVM의 Class Loader는 .class파일을 Runtime Area에 올려 메모리를 할당하고, 자원을 검증하고, static 변수를 초기화 한다.
*Byte Code는 JVM이 이해할 수 있는 명령어 집합이다.
- JVM은 Runtime Area에 올라온 ByteCode를 JIT 컴파일 방식으로 실행한다.
- Interpreter와 JIT Compiler의 역할은?
- Interpreter는 ByteCode를 한줄씩 읽어가며 수행한다.
- JIT는 프로그램을 실행하며 코드를 분석하고 최적화를 수행한다.
- 일반적으로 초기 실행단계에서 Interpreter를 사용하여 프로그램을 빠르게 실행하고 JIT는 프로그램이 더 많은 시간을 실행하면서 최적화를 수행한다.
- GC(Grabage Collector)은 더 이상 사용되지 않는 객체 또는 메모리 누수로부터 발생한 메모리를 해제하고 개발자가 명시적으로 메모리 할당과 해제를 줄여주며 프로그램의 성능을 향상시킨다. GC만 하더라도 하나의 게시글을 작성할 수 있을정도로 깊이 알아야 하므로 이 정도만 하고 넘어가겠다.
Runtime Data Areas

프로그램을 실행하기 위해 OS로부터 할당받은 메모리 공간이 Runtime Data Area이다.
각각의 Thread는 Heap과 Method Area의 자원을 공유할 수 있지만 다른 Thread의 자원을 공유할 수는 없다.
각각의 영역이 어떤 역할을 하는지 알아보자.
- Method Area: 인스턴스 생성을 위한 객체 구조, 생성자, 필드 등이 저장된다. static 변수, Class 데이터들도 이곳에서 관리가 된다. JVM당 하나만 구동 시작시에 생성 되며 종료 시까지 유지되는 공통 영역이다.
- Heap: 코드 실행을 위한 Java 객체가 탑재된다. 문자열에 대한 정보를 가진 String Pool과 실제 데이터를 가진 인스턴스, 배열등이 저장된다. 우리가 흔히 보는 OOM(Out Of Memory)는 Heap 영역이 가득차기 때문에 발생한다. GC가 주시하며 메모리 해제를 주로 수행하는 영역이기도 하다. 각각의 Thread가 객체를 참조하므로 Thread Unsafe하다.
- Stack: 각 Thread별로 할당되므로 Heap보다 비교적 빠르고 Thread Safe하다. 메소드를 호출할때 마다 Frame을 push하고 메소드가 마무리되면 Frame을 pop한다. Stack처럼 FILO이다. Local Variables Array, Operand Stack, Constant Pool Reference로 구성되어 있다.
- Local Variables Array: 메소드안 지역변수의 값과 인덱스를 저장
- Operand Stack: 연산을 위해 바이트 코드 명령어가 할당
- Constant Pool Reference: Constanc Pool참조를 위한 공간
- Native Method Stack: 순수하게 Java로 구성된 코드만 사용할수 없는 경우 다른 언어로 작성된 메소드를 호출해야 한다. 이럴 때 이 공간을 사용하며 C Stack으로 부르기도 한다.
- PC(Program Counter) Registers: Thread가 switching이 일어날 때 최근에 실행 중인 명령어 주소값을 저장하는 공간.