자바

자바의 컴파일, 클래스 로딩, 실행 구조 정리

정재익 2026. 1. 3. 17:00


1. 자바 실행 구조 개요

일반적으로 프로그래밍 언어는 컴파일 → 링크 → 실행(런타임) 단계로 나뉜다.
자바는 C/C++과 달리
컴파일 시점과 실행 시점이 명확히 분리된 구조를 가진다.
자바에서는
.java 파일을 컴파일하면 .class 파일이 생성되고,
이 .class 파일은 자바 바이트 코드로 이루어져 있다.


2. 자바 컴파일 단계

.java 파일은 javac에 의해 컴파일되어 .class 파일이 된다.

  • .class 파일의 내용은 자바 바이트 코드
  • 클래스 로더가 실제로 로딩하는 대상은 .class 파일이다

바이트 코드는 사람이 직접 분석하기는 어렵다.
일반적으로 16진수 형태의 숫자 나열이기 때문에 그대로 읽는 것은 힘들다.
다만,

  • javap -c 명령어로 디스어셈블 가능
  • IntelliJ에서는 “바이트코드 보기” 메뉴 제공

이를 통해 바이트코드를 분석할 수 있다.


3. 자바 바이트 코드와 JVM 명령어

자바 바이트 코드에는 JVM 명령어들이 포함되어 있다.

  • LDC : 문자열 등을 상수 풀에 로드
  • INVOKE* 계열 : 메서드 호출(바인딩) 과 관련

이 바이트 코드는 바로 CPU에서 실행되지 않는다.


4. JVM 실행 엔진: 인터프리터와 JIT 컴파일러

JVM은 가상 머신이기 때문에
실제 실행은 리얼 머신의 CPU가 수행한다.
이때 바이트 코드를 CPU가 이해할 수 있도록 처리하는 것이
JVM 내부의 실행 엔진(Execution Engine) 이다.
실행 엔진은 두 가지 방식으로 동작한다.

  • 인터프리터
    • 바이트 코드를 한 줄씩 해석하며 실행
  • JIT 컴파일러
    • 자주 실행되는 코드를 미리 기계어로 컴파일
    • 이후 재사용

자주 등장하는 코드는 JIT 컴파일러가 기계어로 번역하여 캐싱하고,
그 외의 코드는 인터프리터가 처리한다.
JIT 컴파일러의 등장 이후로 JVM 성능은 크게 향상되었다.


5. 클래스 로더의 역할

클래스 로더는 이름을 알고 있는 특정 클래스에 대한 정의를 가져오는 역할을 수행한다.

  • .class 파일을 메모리로 로딩
  • 로컬 파일 시스템뿐 아니라 네트워크를 통해서도 로딩 가능

클래스 로더는 실행을 담당하지 않는다.
오직 클래스 정의를 JVM에 전달하는 역할만 한다.


6. 클래스 로더 계층 구조

자바에는 여러 계층의 클래스 로더가 존재한다.

  • 부트스트랩 클래스 로더
    • JVM 핵심 라이브러리 로딩
    • (예: rt.jar, tools.jar 등)
  • 플랫폼 클래스 로더
  • 애플리케이션 클래스 로더

이 계층 구조를 통해 클래스 로딩의 책임이 분리된다.


7. 클래스 로딩과 링킹 단계

자바에서 클래스 로딩과 링킹은 모두 런타임에 이루어진다.

7-1. 로딩 (Loading)

  • .class 파일을 읽어 메모리에 올림

7-2. 링킹 (Linking)

링킹은 다시 세 단계로 나뉜다.

검증 (Verification)

  • JVM 명세의 규칙과 제약을 만족하는지 확인
  • 메타데이터 및 보안 검증 수행
  • C/C++에 비해 자바가 안정적인 이유 중 하나

JNI를 통해 네이티브 자원에 접근할 경우
시스템에 손상을 줄 수 있는 위험이 존재한다.

준비 (Preparation)

  • 클래스의 메타데이터 관리
  • 로드된 클래스의 정적 변수(static)를
    • 기본값(0, null)으로 초기화
  • 아직 인스턴스화는 이루어지지 않은 상태
  • static final 상수만 실제 값이 할당됨

해석 (Resolution)

  • 상수 풀에 있는 심벌 참조를 직접 참조로 대체

8. 초기화와 객체 생성

클래스가 실제로 사용되기 시작하면 초기화 단계가 수행된다.

  • new 연산 시
    1. 메모리 공간을 0으로 초기화
    2. 생성자 호출
    3. 객체가 완전히 사용 가능해짐

이후 객체는 정상적으로 사용된다.


9. 언로딩과 메타데이터

사용이 끝난 클래스는 언로딩될 수 있다.
클래스 관련 정보는 메타데이터로 관리되며,
JVM은 이를 기반으로 메모리 관리 및 GC를 수행한다.


10. 자바가 유연한 이유

클래스 로딩과 링킹이 모두 런타임에 이루어지기 때문에

  • 실행 속도는 상대적으로 느릴 수 있지만
  • 대신 유연성과 확장성을 얻는다

이 구조 덕분에

  • 구현체를 런타임에 선택
  • 다형성, DI, 전략 패턴 등이 가능

자바의 핵심 장점은 바로 이 구조에서 나온다.