[CS] JVM
🚀 이 주제를 선택한 이유 & 학습 목표
- 선택 배경: 프로젝트를 진행하면서 발생하는 문제를 이해하기 위해 기본적인 Spring과 JVM에 대해 학습 필요성을 느꼈다
- 학습 목표: JVM의 동작 방식에 대한 전체적인 이해를 하자
📚 핵심 개념 및 원리
1. 주요 용어 정의
- JVM (Java Virtual Machine) : 자바 바이트 코드를 실행하는 가상 머신, 운영체제와 하드웨어에 독립적으로 자바 프로그램을 실행할 수 있게 한다
- JRE (Java Runtime Environment) : JVM + 자바 클래스 라이브러리 (API)
- JDK (Java Development Kit) : JRE + 개발 도구 (컴파일러, 디버거 등)
- JNI (Java Native Interface) : JVM 위에서 네이티브 언어로 작성된 프로그램 및 라이브러리와 상호작용할 수 있도록 하는 인터페이트
2. 핵심 원리/동작 방식

- Java 프로그램 실행 과정
- 자바 컴파일러가 소스코드(.java) 파일을 JVM이 이해할수 있는 바이트코드(.class)로 변환
- 프로그램 실행 시, 클래스 로더가 이 .class 파일을 JVM의 런타임 데이터 영역으로 로드
- 실행 엔진이 로드된 바이트 코드를 해석하고 실행
- 클래스 로더 시스템
- 컴파일된 자바 바이트코드를 런타임 시점에서 JVM의 메모리에 적재하는 역할
- 애플리케이션 실행 시 필요할 때 동적으로 메모리에 올라간다
- 처음 참조할 때 해당 클래스로 로드하고 링크한다
- 로딩 : 클래스 로더가 바이트파일을 읽어 해당 클래스 타입의 class 객체를 생성하고, 클래스 정보를 런타임 데이터 영역 (OS가 JVM에 할당해준 메모리), 특히 메서드 영역에 저장 (추상적 식별 정보를 런타임 상수 풀에 복사)
- 링킹 : 로드된 클래스 또는 인터페이스를 실행 가능한 상태로 만드는 과정
- 검증 : 로드된 바이트파일이 JVM 명세에 따라 유효한지, 보안상 문제없는지 확인
- 준비 : 클래스 변수(static)와 클래스에서 사용하는 메서드 및 인터페이스에 필요한 메모리를 할당하고 기본값으로 초기화
- 분석 : 로딩 단계에서 복사된 추상 식별 정보를 실제 메모리 주소 값으로 변환 (new or instanceof 연산)
- 초기화 : 클래스 변수를 코드에 명시한 값으로 초기화하고, static 블록 실행
- 컴파일된 자바 바이트코드를 런타임 시점에서 JVM의 메모리에 적재하는 역할
- 런타임 데이터 영역
- OS가 JVM에 할당해준 메모리 공간
- 메서드 영역 (메서드 / 스테틱 / 클래스)
- 모든 스레드가 공유하는 영역, JVM 시작 시 생성
- 클래스 로더에 의해 로드된 모든 클래스의 메타데이터 등 정보를 저장
- 런타임 상수 풀 : 각 클래스와 인터페이스의 상수 풀 테이블을 런타임 시 구현한 것
- 힙 영역
- 모든 스레드가 공유하며, JVM 시작 시 생성
- new 키워드로 생성된 객체 인스턴스와 배열이 저장되는 공간
- GC의 주요 관리 대상
- JVM 스택
- 각 쓰레드마다 개별적 생성, 쓰레드의 생명 주기와 동일
- 메서드 호출 시 프레임을 저장하고 관리
- 프레임 : 메서드가 호출될 때마다 생성되며, 해당 메서드의 작업 수행에 필요한 데이터를 담음
- PC 레지스터 : 쓰레드마다 생성, 현재 실행중인 JVM 명령어의 주소를 저장
- 네이티브 메서드 스택 : 자바외의 언어로 작성된 네이티브 코드를 실행할 때 사용되는 메모리, JNI를 통해 호출된 메서드의 정보를 저장
- 실행 엔진
- 바이트 코드를 명령어 단위로 읽어 실행
- 인터프리터 : 바이트코드를 하나씩 읽고 해석하여 실행
- JIT 컴파일러 : 인터프리터의 단점을 보안하기 위해 나온 컴파일러. 반복적으로 수행되는 바이트 코드를 감지하여 네이티브 코드로 컴파일 해두고 캐싱된 네이티브 코드를 직접 실행 ( 캐싱은 네이티브 메모리 내부의 코드 캐시에 저장)
- GC(Garbage Collector) : 힙 영역의 객체 중 더 이상 참조되지 않는 객체를 찾아 메모리에서 해제
- 바이트 코드를 명령어 단위로 읽어 실행
🤔 나의 이해와 생각 정리 (회고)
핵심 요약: .java -> (컴파일러) -> .class(바이트코드) -> (클래스로더) -> (실행엔진) -> 실행
새롭게 깨달은 점: GC가 OS레벨에서 작동하는 것이 아니라 JVM에서 작동한다. 그리고 보통 메모리에 할당하는 영역인 객체나 배열에 대해서 직접적인 하드웨어 이전에 JVM에서 할당한 힙과 스택 영역에 할당한다.
더 궁금해진 점 / 의문점: 실제 컴파일러와 클래스 로더에 대한 이해가 더 필요해 보인다. 그리고 실질적으로 가상 머신이라는 것이 임의로 어떤 동작을 통해서 하드웨어의 일정 부분을 할당시켜 동작을 할텐데 이러한 상세한 동작 방식에 대해서도 이해가 필요해보인다.
📖 더 학습할 내용 및 참고 자료
추가 학습 희망 분야: GC, JIT, JMM, Spring의 멀티쓰레딩 환경과 JVM 의 관계, 하드웨어와 JVM의 관계
✨ 마무리하며
JVM에 대해 막연한 부분을 정리했다. 학습 과정에서 OS에서 말그대로 가상머신에 대해서 어떤식으로 사용되는 하드웨어환경에 맞춰 할당을 해주고, 이러한 Spring과 같은 프레임워크가 만들어지기 이전의 서블릿과 JSP환경에서 어떻게 사용되었는지 궁금하다.
실제로 사용하는 프레임워크가 왜 사용되었는지 이해했다. 단순히 동작을 떠나 WAS와 기타 라이브러리에 대한 어떤 종합적인 구심점이 필요해보인다.
'Study > CS' 카테고리의 다른 글
| 정렬 3편 (힙(Heap)과 힙 정렬) (2) | 2025.07.29 |
|---|---|
| 정렬 2편 (분할 정복: 병합 정렬, 퀵 정렬) (2) | 2025.07.29 |
| 정렬 1편 (버블 정렬, 선택 정렬, 삽입 정렬) (3) | 2025.07.29 |
| String과 StringBuilder (0) | 2025.06.27 |
| Spring (IoC, Bean, AOP) (1) | 2025.05.27 |