JVM은 'Java Virtual Machine'의 줄임말로 자바를 실행하기 위한 가상머신(컴퓨터)입니다.
컴퓨터를 사용해서 Java를 실행하기 위한 가상의 컴퓨터라고 생각하면 됩니다. 즉, 컴퓨터 속의 컴퓨터입니다.

Java는 OS에 종속받지 않고 어느 OS나 실행가능하다는 특징을 가지고 있습니다. OS에 종속받지 않을 수 있는 이유가 JVM이 있기 때문입니다. 다만 JVM은 OS와 직접 소통하기때문에 각 OS규격에 맞는 JVM이 필요합니다.
하지만 Java를 개발한 썬 마이크로시스템즈(Sun Microsystems, Inc.)에서 이미 주요 OS용 JVM을 제공하고 있기 때문에 걱정할 필요가 없습니다.
Java 이전에는 프로그래머가 모든 프로그램의 메모리를 관리했어야 했습니다. 그러나 자바는 JVM이 프로그램 메모리를 대신 관리해줍니다.
가비지 컬렉션(Garbage Collection. 이하 GC)프로세스를 통해 메모리를 관리하며, 가비지 컬렉션은 자바 프로그램에서 사용되지 않는 메모리를 지속적으로 찾아내서 제거해줍니다.
💡 자바는 실행 시에 해석되기 때문에 속도가 느리다고 알려져있습니다. 그러나 C나 Rust 못지않게 빠르며, 대부분의 다른 언어보다 빠른 언어 중 하나 입니다. 최근엔 바이트코드(Compiled Java Code)를 하드웨어의 기계어로 바로 변환해주는
JIT컴파일러와 최적화 기술도 적용되어 최적화된 성능을 출력할 수 있습니다. 그럼에도 불구하고 C나 Rust에 비하면 메모리를 많이 소모합니다.

Java코드(*.java)는 CPU가 인식을 하지 못하므로 기계어로 컴파일하는 과정이 필요합니다. 하지만 JVM은 사용자 언어인 원시코드(*.java)를 인식하지 못한다. 그래서 JVM으로 해석하기 전에 Compiler를 통해 JVM이 인식할 수 있는 Java ByteCode(*.class)로 변환하는 과정을 거칩니다.
변환된 ByteCode도 OS에서 이해할 수 있는 기계어가 아니기 때문에 JVM이 OS가 이해할 수 있도록 'ByteCode -> 기계어'로 해석해줍니다.
자바코드가 이런 과정으로 컴파일 되기 때문에 "Write once, run anywhere.(한 번 작성하면 어디서든 실행된다."이 가능하게 됩니다.

JVM은 크게 다음과 같이 구성되어 있습니다.
자바는 동적 로드를 합니다. 이 말은 컴파일 타임이 아니라 런타임에 클래스를 처음으로 참조할 때 해당 클래스를 로드하고 링크한다는 말입니다. 이 동적 로드를 담당하는 부분이 클래스 로더(Class Loader)다.

클래식 로더가 로드되지 않은 클래스를 찾으면 다음과 같은 과정을 거쳐 처리합니다.
.*class)를 파일에서 가져와서 JVM의 메모리에 로드.
런타임 데이터 영역은 JVM이라는 프로그램이 운영체제 위에서 실행되면서 할당받는 메모리 영역입니다.
💡 힙 영역에 문자열을 위한 힙 영역이 따로 존재
- new String("김춘박"); <- 힙 영역에 하나의 객체로 할당
- String str = "김춘식"; <- 힙 영역의 문자열 영역 내부에 할당
- 해당 문자열을 참조시 참조 변수에는 해당 문자열의 힙메모리 주소가 할당됨
💡 스레드(Thread)
- 하나의 프로세스 안에서 실행되는 흐름의 단위.
모든 프로세스에는 한 개 이상의 스레드가 포함되어 있다. 두 개 이상의 스레드를 가지는 프로세스를 멀티 스레드 프로세스(Multi Thread Process)라고 한다.
💡 프로세스(Process)
- 현재 실행중인 프로그램.
프로그램 파일이 주기억장치(RAM)에 적재되어 CPU에 의해 실행 중인 것을 말한다.
클래스 로더를 통해 JVM 내의 런타임 데이터 영역에 배치된 ByteCode는 실행 엔진에 의해 실행된다. 실행 엔진은 자바 바이트코드를 명령어 단위로 읽어서 실행합니다.
캐시(Cache)에 보관하기 때문에 한 번 컴파일된 코드를 계속 빠르게 직접 실행할 수 있다.