1. JVM (Java Virtual Machine) 이란?
JVM은 OS를 대신해서 컴파일된 자바 바이트 코드를 실행하는 가상의 운영체제이다.
즉, OS에 종속받지 않고 CPU가 JAVA를 인식, 실행할 수 있게 하는 가상 컴퓨터이다.
JVM에 의해 JAVA는 '운영체제에 독립적'이라는 장점을 가진다.
JVM은 자바 언어에서만 사용하는 것이 아니다. 코틀린, 스칼라 언어에서도 JVM 동작 방식을 그대로 따른다.
JVM의 역할은 자바 애플리케이션을 클래스 로더를 통해 읽어 자바 API와 함께 실행하는 것이다.
2. 자바 코드가 컴파일 되는 과정

위의 동작처럼 Java 소스코드, 즉 원시코드(*.java)는 CPU가 인식을 하지 못하므로 기계어로 컴파일을 해줘야 한다.
이 때, Java는 이 JVM 이라는 가상머신을 먼저 거친 후 최종적으로 OS에 도달하기 때문에 OS가 인식할 수 있는 기계어로 바로 컴파일 되는게 아니라 JVM이 인식할 수 있는 Java bytecode(*.class)로 변환된다.
이 과정을 수행하는 것이 javac.exe이다. JDK를 설치하면 자바 컴파일러인 javac.exe는 bin 에 존재한다.
즉, JDK에 Java compiler가 포함되어 있다.따라서 javac 명령어를 통해 .java를 .class로 컴파일 할 수 있다.
$ javac testcode.java
$ java testcode <== .class 파일
"HELLO WORLD"
변환된 bytecode는 기계어가 아니기 때문에 OS가 해석할 수 없다. 그래서 JVM가 Byte Code를 OS가 해석할 수 있는 기계어(Binary Code)로 변환한다. 이것을 간단하게 표현하면 아래와 같다.
.java 소스코드 → (Javac 컴파일러 = JDK 필요) → .class 바이트코드 → (JVM이 실행 = JRE 필요)
📁 .java와 .class 파일의 저장 위치
src/Hello.java: 소스코드 위치
bin/Hello.class: 바이트코드(JVM이 읽는 컴파일된 코드) 저장 위치
3. JDK, JRE, JVM 관계


구성 요소 | 포함 내용 | 역할 |
JDK (Java Development Kit) | JRE + 컴파일러(javac), 디버거, 개발 도구 | 개발자용: .java 파일을 .class로 컴파일 가능 |
JRE (Java Runtime Environment) | JVM + 라이브러리(rt.jar 등) | 사용자용: .class 실행 가능 (컴파일은 불가) |
JVM (Java Virtual Machine) | 클래스 로더 + 런타임 데이터 영역 + 실행 엔진 | 실행기: 바이트코드를 OS에 맞게 실행 |
✅ JRE가 필요한 시점은?
👉 .class 파일(바이트코드)을 실행할 때
즉, 이미 컴파일된 자바 프로그램을 실행하려면 JRE만 있으면 충분하다.
4. JVM 의 구조

이처럼 JVM은 아래와 같이 구성되어 있다.
✔ 클래스 로더(Class Loader)
✔ 실행 엔진(Execution Engine)
- 인터프리터(Interpreter)
- JIT 컴파일러(Just-in-Time Compiler)
- 가비지 컬렉터(Garbage collector)
✔ 런타임 데이터 영역 (Runtime Data Area)
- 메소드 영역
- 힙 영역
- PC Register
- 스택 영역
- 네이티브 메소드
✔ JNI - 네이티브 메소드 인터페이스 (Native Medthod Interface)
✔ 네이티브 메소드 라이브러리 (Native Method Library)
4-1. 클래스 로더
클래스 로더는 JVM 내로 클래스 파일(*.class)을 동적으로 로드하고, 링크를 통해 배치하는 작업을 수행하는 모듈이다.
즉, 로드된 바이트 코드(.class)들을 엮어서 JVM의 메모리 영역인 Runtime Data Areas에 배치한다. 클래스를 메모리에 올리는 로딩 기능은 한번에 메모리에 올리지 않고, 어플리케이션에서 필요한 경우 동적으로 메모리에 적재한다.
4-2. 실행 엔진
실행 엔진은 클래스 로더를 통해 런타임 데이터 영역에 배치된 바이트 코드를 명령어 단위로 읽어서 실행한다.
이 수행 과정에서 실행 엔진은 인터프리터와 JIT 컴파일러 두 가지 방식을 혼합하여 바이트 코드를 실행한다.
✅ 인터프리터(Interpreter)
실행 엔진은 기본적으로 자바 바이트 코드를 명령어 단위로 읽어서 실행한다.
하지만 한 줄씩 수행하기 때문에 느리다. 이 단점을 보완하는 것이 JIT이다.
✅ JIT (Just-In-Time Compiler)
JIT는 반복되는 코드를 발견해서 바이트 코드 전체를 컴파일 한 후 Native Code로 변경하고 이후에는 해당 메서드는 더 이상 인터프리팅 하지 않고 캐싱해 두었다가 네이티브 코드로 직접 실행하는 것이다. 인터프리터 방식으로 실행하다가 적절한 시점에 바이트 코드 전체를 컴파일하여 기계어로 변경하고, 이후에는 해당 더 이상 인터프리팅 하지 않고 기계어로 직접 실행하는 방식이다. 이렇게 하는 것이 바이트 코드를 인터프리팅하는 것보다 훨씬 오래걸리므로 한 번만 실행되는 코드라면 컴파일 하지 않고 인터프리팅하는 것이 유리하다.
✅ 가비지 컬렉터(Garbage collector)
더이상 사용되지 않는 인스턴스를 찾아 메모리에서 삭제한다.
4-3. Java Runtime Data Areas (= 자바 실행 시 메모리 구조)
자바 프로그램이 실행되면, JVM은 메모리를 아래처럼 구분해서 사용한다.
1) Method Area (메서드 영역)
- "설계도와 설명서 보관소"
- 클래스 정보 저장: 클래스 이름, 상속관계, 변수와 메서드 정보
- static 변수와 static 메서드도 여기 저장
- 공용 저장소: 모든 쓰레드가 공유
- 한 번 로딩된 클래스는 여기 저장되며, JVM이 종료될 때까지 유지됨
class Dog {
static int count = 0;
String name;
}
Dog 클래스 자체 정보, count 같은 static 변수 → 메서드 영역에 저장
2) Heap (힙)
- 🧸 "실제 객체가 살아 숨 쉬는 공간"
- new 키워드로 만든 객체(instance)가 저장되는 곳
- 참조형 변수(클래스, 배열 등)의 실제 데이터 저장소
- 모든 쓰레드가 공유
Dog d = new Dog();
d라는 참조 변수는 스택에, new Dog()로 만들어진 객체는 힙에 저장됨

3) Java Stack (자바 스택)
- "메서드 실행 정보 저장소 (1명당 1개씩 지급)"
- 각 쓰레드마다 따로 있음
- 메서드가 호출되면, 스택 프레임이 위에 차곡차곡 쌓임 (push)
- 프레임에는 지역 변수, 매개변수, 리턴값 등이 저장됨
- 메서드가 끝나면 해당 프레임은 제거됨 (pop)
void greet(String name) {
String message = "Hello " + name;
}
name, message는 이 메서드가 실행되는 동안 스택에 저장됨
4) PC Registers (프로그램 카운터 레지스터)
- 🎯 "지금 어디 실행 중인지 기억하는 눈금자"
- 각 쓰레드마다 존재
- 현재 쓰레드가 실행 중인 바이트코드의 주소(명령 위치)를 저장
- 마치 책갈피처럼, "지금 이 명령어 실행 중이야"라고 표시
- main() 안에서 greet() 호출 → greet()의 첫 줄로 PC 레지스터가 이동
5) Native Method Stack (네이티브 메서드 스택)
- 자바 이외의 언어(C, C++, 어셈블리 등)로 작성된 네이티브 코드를 실행하기 위한 공간
- 자바 코드가 컴파일되어 생성되는 바이트 코드가 아닌, 실제로 실행할 수 있는 기계어로 작성된 프로그램이 실행된다.
- 대표적으로JNI (Java Native Interface)로 호출된 코드가 이 영역에 저장된다.
System.arraycopy(...);
이건 실제로는 C로 작성된 메서드이고, JVM은 네이티브 메서드 스택을 써서 처리함
4-4. JNI (Java Native Interface)
JNI는 자바가 다른 언어 (C / C++) 로 만들어진 어플리케이션과 상호 작용할 수 있는 인터페이스를 제공하는 프로그램이다.
즉, 네이티브 함수 호출용으로 JVM이 Native Method를 적재하고 수행할수 있도록한다.
4-5. JNI (Java Native Interface)
자바 코드가 운영체제 의존적인 C/C++ 라이브러리와 통신할 수 있게 해주는 브리지 역할을 한다.
자바는 플랫폼 독립적이지만, 일부 기능(CPU 제어, 그래픽, 장치 드라이버 등)은 OS 의존적이라서 자바만으로는 처리 불가하다.
이럴 때 C/C++로 구현된 시스템 레벨의 코드를 자바에서 호출해야 할 때 JNI를 사용할 수 있다.
즉, OS 의존적인 C/C++ 라이브러리를 DLL(Windows), .so(Linux), .dylib(Mac) 생성하는 곳이다.
✅ JNI 작동 흐름
Java Code (.java)
↓ javac
Bytecode (.class)
↓
native 메서드 선언 (native 키워드)
↓
JNI Header 생성 (javah 명령어 또는 javac -h)
↓
C/C++ 구현 (.c, .cpp)
↓ 컴파일
네이티브 라이브러리 생성 (.dll, .so, .dylib)
↓
Java에서 System.loadLibrary("이름") 호출
참고 자료
☕ JVM 내부 구조 & 메모리 영역 💯 총정리
저번 포스팅에서는 JRE / JDK / JVM에 대해서 간략하게 알아보는 시간을 가졌다면, 이번 포스팅에서는 JVM의 내부 구조에 대해 좀 더 자세하게 알아보도록 할 예정이다. JVM(자바 가상 머신)은 자바 언
inpa.tistory.com
[JAVA기초] JVM이란?
Java Virtual Machine의 줄임말인 JVM은 OS에 종속받지 않고 CPU가 JAVA를 인식, 실행할 수 있게 하는 가상 컴퓨터입니다.그렇기 때문에, JAVA언어는 JVM에 의해 "운영체제에 독립적"이라는 장점을 가질 수
velog.io
'Java' 카테고리의 다른 글
[Java] (상속)변수는 메서드처럼 오버라이딩 되지 않는다. (3) | 2025.06.24 |
---|---|
[Java] 자바에서 this, 생성자 호출시 this() (3) | 2025.06.22 |
[Java] 자바의 예외 - Exception, RuntimeException 차이 (5) | 2025.04.22 |
[Java] 자바 컴파일하기, JDK, bin, java, javac 확장자 뜻 (1) | 2025.04.18 |
[Java] JDK, JRE, JVM 개념 & 차이 등 정리 (4) | 2025.04.02 |
1. JVM (Java Virtual Machine) 이란?
JVM은 OS를 대신해서 컴파일된 자바 바이트 코드를 실행하는 가상의 운영체제이다.
즉, OS에 종속받지 않고 CPU가 JAVA를 인식, 실행할 수 있게 하는 가상 컴퓨터이다.
JVM에 의해 JAVA는 '운영체제에 독립적'이라는 장점을 가진다.
JVM은 자바 언어에서만 사용하는 것이 아니다. 코틀린, 스칼라 언어에서도 JVM 동작 방식을 그대로 따른다.
JVM의 역할은 자바 애플리케이션을 클래스 로더를 통해 읽어 자바 API와 함께 실행하는 것이다.
2. 자바 코드가 컴파일 되는 과정

위의 동작처럼 Java 소스코드, 즉 원시코드(*.java)는 CPU가 인식을 하지 못하므로 기계어로 컴파일을 해줘야 한다.
이 때, Java는 이 JVM 이라는 가상머신을 먼저 거친 후 최종적으로 OS에 도달하기 때문에 OS가 인식할 수 있는 기계어로 바로 컴파일 되는게 아니라 JVM이 인식할 수 있는 Java bytecode(*.class)로 변환된다.
이 과정을 수행하는 것이 javac.exe이다. JDK를 설치하면 자바 컴파일러인 javac.exe는 bin 에 존재한다.
즉, JDK에 Java compiler가 포함되어 있다.따라서 javac 명령어를 통해 .java를 .class로 컴파일 할 수 있다.
$ javac testcode.java $ java testcode <== .class 파일 "HELLO WORLD"
변환된 bytecode는 기계어가 아니기 때문에 OS가 해석할 수 없다. 그래서 JVM가 Byte Code를 OS가 해석할 수 있는 기계어(Binary Code)로 변환한다. 이것을 간단하게 표현하면 아래와 같다.
.java 소스코드 → (Javac 컴파일러 = JDK 필요) → .class 바이트코드 → (JVM이 실행 = JRE 필요)
📁 .java와 .class 파일의 저장 위치
src/Hello.java: 소스코드 위치
bin/Hello.class: 바이트코드(JVM이 읽는 컴파일된 코드) 저장 위치
3. JDK, JRE, JVM 관계


구성 요소 | 포함 내용 | 역할 |
JDK (Java Development Kit) | JRE + 컴파일러(javac), 디버거, 개발 도구 | 개발자용: .java 파일을 .class로 컴파일 가능 |
JRE (Java Runtime Environment) | JVM + 라이브러리(rt.jar 등) | 사용자용: .class 실행 가능 (컴파일은 불가) |
JVM (Java Virtual Machine) | 클래스 로더 + 런타임 데이터 영역 + 실행 엔진 | 실행기: 바이트코드를 OS에 맞게 실행 |
✅ JRE가 필요한 시점은?
👉 .class 파일(바이트코드)을 실행할 때
즉, 이미 컴파일된 자바 프로그램을 실행하려면 JRE만 있으면 충분하다.
4. JVM 의 구조

이처럼 JVM은 아래와 같이 구성되어 있다.
✔ 클래스 로더(Class Loader)
✔ 실행 엔진(Execution Engine)
- 인터프리터(Interpreter)
- JIT 컴파일러(Just-in-Time Compiler)
- 가비지 컬렉터(Garbage collector)
✔ 런타임 데이터 영역 (Runtime Data Area)
- 메소드 영역
- 힙 영역
- PC Register
- 스택 영역
- 네이티브 메소드
✔ JNI - 네이티브 메소드 인터페이스 (Native Medthod Interface)
✔ 네이티브 메소드 라이브러리 (Native Method Library)
4-1. 클래스 로더
클래스 로더는 JVM 내로 클래스 파일(*.class)을 동적으로 로드하고, 링크를 통해 배치하는 작업을 수행하는 모듈이다.
즉, 로드된 바이트 코드(.class)들을 엮어서 JVM의 메모리 영역인 Runtime Data Areas에 배치한다. 클래스를 메모리에 올리는 로딩 기능은 한번에 메모리에 올리지 않고, 어플리케이션에서 필요한 경우 동적으로 메모리에 적재한다.
4-2. 실행 엔진
실행 엔진은 클래스 로더를 통해 런타임 데이터 영역에 배치된 바이트 코드를 명령어 단위로 읽어서 실행한다.
이 수행 과정에서 실행 엔진은 인터프리터와 JIT 컴파일러 두 가지 방식을 혼합하여 바이트 코드를 실행한다.
✅ 인터프리터(Interpreter)
실행 엔진은 기본적으로 자바 바이트 코드를 명령어 단위로 읽어서 실행한다.
하지만 한 줄씩 수행하기 때문에 느리다. 이 단점을 보완하는 것이 JIT이다.
✅ JIT (Just-In-Time Compiler)
JIT는 반복되는 코드를 발견해서 바이트 코드 전체를 컴파일 한 후 Native Code로 변경하고 이후에는 해당 메서드는 더 이상 인터프리팅 하지 않고 캐싱해 두었다가 네이티브 코드로 직접 실행하는 것이다. 인터프리터 방식으로 실행하다가 적절한 시점에 바이트 코드 전체를 컴파일하여 기계어로 변경하고, 이후에는 해당 더 이상 인터프리팅 하지 않고 기계어로 직접 실행하는 방식이다. 이렇게 하는 것이 바이트 코드를 인터프리팅하는 것보다 훨씬 오래걸리므로 한 번만 실행되는 코드라면 컴파일 하지 않고 인터프리팅하는 것이 유리하다.
✅ 가비지 컬렉터(Garbage collector)
더이상 사용되지 않는 인스턴스를 찾아 메모리에서 삭제한다.
4-3. Java Runtime Data Areas (= 자바 실행 시 메모리 구조)
자바 프로그램이 실행되면, JVM은 메모리를 아래처럼 구분해서 사용한다.
1) Method Area (메서드 영역)
- "설계도와 설명서 보관소"
- 클래스 정보 저장: 클래스 이름, 상속관계, 변수와 메서드 정보
- static 변수와 static 메서드도 여기 저장
- 공용 저장소: 모든 쓰레드가 공유
- 한 번 로딩된 클래스는 여기 저장되며, JVM이 종료될 때까지 유지됨
class Dog { static int count = 0; String name; }
Dog 클래스 자체 정보, count 같은 static 변수 → 메서드 영역에 저장
2) Heap (힙)
- 🧸 "실제 객체가 살아 숨 쉬는 공간"
- new 키워드로 만든 객체(instance)가 저장되는 곳
- 참조형 변수(클래스, 배열 등)의 실제 데이터 저장소
- 모든 쓰레드가 공유
Dog d = new Dog();
d라는 참조 변수는 스택에, new Dog()로 만들어진 객체는 힙에 저장됨

3) Java Stack (자바 스택)
- "메서드 실행 정보 저장소 (1명당 1개씩 지급)"
- 각 쓰레드마다 따로 있음
- 메서드가 호출되면, 스택 프레임이 위에 차곡차곡 쌓임 (push)
- 프레임에는 지역 변수, 매개변수, 리턴값 등이 저장됨
- 메서드가 끝나면 해당 프레임은 제거됨 (pop)
void greet(String name) { String message = "Hello " + name; }
name, message는 이 메서드가 실행되는 동안 스택에 저장됨
4) PC Registers (프로그램 카운터 레지스터)
- 🎯 "지금 어디 실행 중인지 기억하는 눈금자"
- 각 쓰레드마다 존재
- 현재 쓰레드가 실행 중인 바이트코드의 주소(명령 위치)를 저장
- 마치 책갈피처럼, "지금 이 명령어 실행 중이야"라고 표시
- main() 안에서 greet() 호출 → greet()의 첫 줄로 PC 레지스터가 이동
5) Native Method Stack (네이티브 메서드 스택)
- 자바 이외의 언어(C, C++, 어셈블리 등)로 작성된 네이티브 코드를 실행하기 위한 공간
- 자바 코드가 컴파일되어 생성되는 바이트 코드가 아닌, 실제로 실행할 수 있는 기계어로 작성된 프로그램이 실행된다.
- 대표적으로JNI (Java Native Interface)로 호출된 코드가 이 영역에 저장된다.
System.arraycopy(...);
이건 실제로는 C로 작성된 메서드이고, JVM은 네이티브 메서드 스택을 써서 처리함
4-4. JNI (Java Native Interface)
JNI는 자바가 다른 언어 (C / C++) 로 만들어진 어플리케이션과 상호 작용할 수 있는 인터페이스를 제공하는 프로그램이다.
즉, 네이티브 함수 호출용으로 JVM이 Native Method를 적재하고 수행할수 있도록한다.
4-5. JNI (Java Native Interface)
자바 코드가 운영체제 의존적인 C/C++ 라이브러리와 통신할 수 있게 해주는 브리지 역할을 한다.
자바는 플랫폼 독립적이지만, 일부 기능(CPU 제어, 그래픽, 장치 드라이버 등)은 OS 의존적이라서 자바만으로는 처리 불가하다.
이럴 때 C/C++로 구현된 시스템 레벨의 코드를 자바에서 호출해야 할 때 JNI를 사용할 수 있다.
즉, OS 의존적인 C/C++ 라이브러리를 DLL(Windows), .so(Linux), .dylib(Mac) 생성하는 곳이다.
✅ JNI 작동 흐름
Java Code (.java) ↓ javac Bytecode (.class) ↓ native 메서드 선언 (native 키워드) ↓ JNI Header 생성 (javah 명령어 또는 javac -h) ↓ C/C++ 구현 (.c, .cpp) ↓ 컴파일 네이티브 라이브러리 생성 (.dll, .so, .dylib) ↓ Java에서 System.loadLibrary("이름") 호출
참고 자료
☕ JVM 내부 구조 & 메모리 영역 💯 총정리
저번 포스팅에서는 JRE / JDK / JVM에 대해서 간략하게 알아보는 시간을 가졌다면, 이번 포스팅에서는 JVM의 내부 구조에 대해 좀 더 자세하게 알아보도록 할 예정이다. JVM(자바 가상 머신)은 자바 언
inpa.tistory.com
[JAVA기초] JVM이란?
Java Virtual Machine의 줄임말인 JVM은 OS에 종속받지 않고 CPU가 JAVA를 인식, 실행할 수 있게 하는 가상 컴퓨터입니다.그렇기 때문에, JAVA언어는 JVM에 의해 "운영체제에 독립적"이라는 장점을 가질 수
velog.io
'Java' 카테고리의 다른 글
[Java] (상속)변수는 메서드처럼 오버라이딩 되지 않는다. (3) | 2025.06.24 |
---|---|
[Java] 자바에서 this, 생성자 호출시 this() (3) | 2025.06.22 |
[Java] 자바의 예외 - Exception, RuntimeException 차이 (5) | 2025.04.22 |
[Java] 자바 컴파일하기, JDK, bin, java, javac 확장자 뜻 (1) | 2025.04.18 |
[Java] JDK, JRE, JVM 개념 & 차이 등 정리 (4) | 2025.04.02 |