Java 프로그램이 실행되는 흐름

자바 프로그램은 단순히 .java 파일을 실행하는 것이 아니라, 컴파일 → 로드 → 실행 이라는 여러 단계를 거쳐 최종적으로 CPU 가 이해할 수 있는 기계어로 변환됩니다.
이 과정에서 JDK, JVM, JRE가 각각 어떤 역할을 하는지 이해하는 것이 중요합니다.
1. 소스 코드 작성과 컴파일
개발자는 자바 소스 파일(.java)을 작성
JDK 에 포함된 javac (Java Compiler)가 소스 코드를 컴파일 하여 JVM이 이해할 수 있는 바이트코드(.class 파일)로 변환
이 바이트 코드는 특정 운영체제에 종속되지 않으며, “Write Once, Run Anywhere”를 가능하게 하는 핵심
즉 .java → .class 변환 과정이 여기서 일어남
2. 클래스 로딩(Class Loading)
프로그램 실행 시 , JVM 의 클래스 로더(Class Loader)가 .class 파일을 읽어 JVM 메모리(Runtime Data Areas)에 올립니다.
클래스 로딩은 정적인 방식이 아닌 동적 로딩을 사용합니다.
동적 로딩이란?
프로그램 시작 시 모든 클래스를 한꺼번에 메모리에 적재하지 않고, 실제로 필요한 순간 (객체 생성, static 변수/ 메서드 참조 시)에만 메모리에 로딩하는 방식.
불필요한 클래스가 메모리에 올라가지 않아, 메모리 효율성이 좋아지고 프로그램 실행 속도도 빨라짐
3. 로딩(Loading) → 링킹(Linking) → 초기화(Initialization)
클래스 로더가 .class 파일을 JVM 메모리에 로드하면, 다음과 같은 단계를 거칩니다.
Loading
- .class파일의 바이트 코드를 읽어, Method Area(메서드 영역) 에 저장
Linking
클래스가 실행 가능한 상태가 되도록 준비하는 과정
Verification(검증) : 클래스 파일이 JVM 명세에 맞게 작성되었는지 확인 → 보안성 확보
Preparation(준비) : static 변수를 위한 메모리 공간을 확보하고 기본값으로 초기화
Resolution(해결) : Constant Pool 에 있는 심볼릭 레퍼런스를 실제 메모리 주소로 변환
Initialization
static 변수에 사용자가 지정한 값 할당
static 블록 실행
이 단계들이 끝나야 클래스가 실행될 준비를 마치게 됩니다.
4. 실행 엔진(Execution Engine)
로드 및 초기화된 클래스의 바이트 코드는 최종적으로 실행 엔진(Execution Engine)에 의해 실행됩니다.
하지만 CPU는 바이트코드를 직접 이해할 수 없기 때문에 기계어 변환 과정이 필요합니다.
JVM은 두가지 방식을 함께 사용합니다.
인터프리터 (Interpreter)
바이트코드를 한줄씩 해석하고 실행
빠른 시작
같은 코드가 반복될 때마다 매번 해석 → 느림
JIT 컴파일러 (Just-In-Time Compiler)
실행 중에 자주 호출되는 메서드를 네이티브 코드로 변환하고 캐싱
한 번 변환되면 이후에는 기계어 그대로 실행 → 빠름
컴파일 과정 자체에 시간이 걸림 (초기 오버헤드 발생)
→ JVM은 처음에는 인터프리터로 실행하고 반복되는 부분은 JIT로 변환하는 하이브리드 방식을 사용하며, 빠른 시작과 높은 성능을 동시에 얻습니다.
5. 실행 환경(JRE와 JVM)
JRE (Java Runtime Environment)
자바 실행에 필요한 기본 라이브러리 + JVM 으로 구성
컴파일된 프로그램을 실행할 수 있는 환경을 제공
JVM (Java Virtual Machine)
바이트코드를 실행하는 가상머신
운영체제 위에서 동작하면서, OS와 프로그램 사이에서 중개자 역할 수행
Subscribe to my newsletter
Read articles from 갱갱 directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
