자바 고급(JAVA)

객체지향 프로그래밍의 이해 - 자바 가상 머신(JVM)

beginner-development 2026. 5. 6. 21:02

JVM이란?

자바 애플리케이션을 실행하기 위한 가상 컴퓨터. 자바 소스 코드를 컴퓨터가 이해할 수 있도록 실행시키는 해석기 역할을 수행한다. .class 파일을 읽고 해석하여 실제 실행하며 운영체제에 독립적으로 동작할 수 있게 만드는 핵심 요소이다. JVM은 자바가 범용성과 이식성을 갖추는 데 결정적 역할을 한다. 단순한 실행 도구가 아닌, 자바 철학의 중심축이라 할 수 있다.

1. 자바의 플랫폼 독립성

- 일반적인 프로그램의 실행 방식

  • 프로그램은 운영체제에게 CPU, 메모리, 입출력 장치 같은 자원을 요청
  • 운영체제마다 요청 방식이 다르므로, 프로그래밍 언어는 일반적으로 운영체제에 종속적이다.

- 자바의 방식

  • 자바는 직접 운영체제와 소통하지 않고 JVM을 통해 간접적으로 운영체제와 상호작용한다.(운영체제마다 별도로 제작)
  • 자바 프로그램 → JVM → 운영체제
  • 이 덕분에 자바는 어떤 OS에서든 한 번 작성한 코드를 모든 환경에서 실행 가능하게 한다.(Write Once, Run Anywhere)

JVM의 운영체제 종속성을 나타내는 이미지

2. JVM 구조

2 - 1. 자바 실행 흐름과 JVM의 역할

  • 자바 코드는 .java파일로 작성되며, 컴파일러(.javac)를 통해 .class바이트코드로 변환된다. 이후 JVM이 실행되며 아래의 단계가 진행된다.
  1. 클래스 로더(Class Loader) : .class 파일을 메모리에 로드
  2. 런타임 데이터 영역(Runtime Data Area)에 메모리 할당
  3. 실행 엔진(Execution Engine)이 바이트코드를 해석하고 실행
    • 인터프리터(Interpreter) : 한 줄씩 실행
    • JIT 컴파일러(Just-In-Time Compiler) : 반복 실행되는 코드를 통째로 기계어로 번역해 성능 향상

2 - 2. JVM 메모리 구조

영역 저장 내용 생명 주기 특징
Method Area 클래스 정보, static, final JVM 종료 시까지 모든 스레드에서 공유
Heap 객체(인스턴스), 배열 GC가 제거 전까지 유연하지만 상대적으로 느림
Stack 지역 변수, 참조 변수, 리턴 값 등 메서드 종료 시 자동 제거 빠르지만 제한적 메모리

 

2 - 3. Stack과 Heap의 동작 방식

  - Stack  : 메서드 실행을 위한 저장소

  • LIFO 구조 (Last In First Out)
  • 메서드 호출 시마다 스택 프레임이 위로 쌓임
  • 프레임 안에는 지역 변수, 매개변수, 연산 중 발생하는 값 등을 저장

  - Heap : 실제 객체 저장소

  • 프로그램 실행 중 생성된 객체는 모두 Heap에 저장
  • 각 참조 변수는 Stack에 존재하고, Heap의 주소를 참조
  • 예시에서 Person()은 Heap에 객체를 생성
  • 참조 변수 p는 Stack에 저장되며, 객체의 주소를 가리킴
Person p = new Person(); //예시

3. Garbage Collection(GC)

3 -1. Garbage Collection이란?

프로그램 실행 도중 더 이상 참조되지 않는 객체를 탐지하고 제거해 메모리를 확보하는 자동화된 메커니즘이다.

  - C/C++ 등은 개발자가 수동으로 메모리 해제를 해야 하지만, 자바는 JVM이 자동으로 관리한다.

  - 메모리 누수, dangling pointer 등 위험을 줄일 수 있다.

###Garbage Collection은 중요한 개념이기에 이 글이 아닌 다른 글에서 따로 다뤄볼 예정이다###

 

4. 메모리 누수 방지 방법(Memory Leak Prevention)

4 - 1. 메모리 누수란?

"더 이상 사용되지 않지만 여전히 참조되고 있어 GC가 수거하지 못하는 객체"를 뜻한다.

  - 참조만 끊기면 GC가 수거할 수 있지만, 의도치 않게 참조가 유지되면 메모리 점유가 계속된다. 이는 OutOfMemoryError의 원인이

    되기도 한다.

 

4 - 2. 메모리 누수가 발생하기 쉬운 상황

  - 요약 정리

원인 구분 설명 예방 전략
컬렉션 누수 객체를 리스트, 맵 등에 추가만 하고 제거하지 않음 사용 종료 시 remove() 명시 호출
static 변수 유지 정적(static)영역은 애플리케이션 종료 시까지 유지됨 캐시 전략 적용, 약한 참조 사용
리스너/콜백 해제 누락 이벤트 객체 등록만 하고 해제하지 않음 removeListener(), WeakReference 사용

※※※ JVM은 강력한 GC를 갖고 있지만, "참조가 끊어져야 수거할 수 있다"는 원칙을 항상 기억하자!

※※※ 메모리 누수는 발견하기 어렵고, 누적되면 시스템 자원을 고갈시켜 애플리케이션의 성능 저하 또는 비정상 종료로 이어질 수 있다.

  - 일상적인 코드에서도 항상 객체 참조 여부를 체크하고, 필요한 경우 해제하는 습관을 들이는 것이 중요하다.