thumbnail
프로그래밍의 구동 방식
Java / Web
2025.07.24.

프로그래밍의 구동 방식: JVM 안에서 일어나는 일들

“코드를 작성하고 실행 버튼을 눌렀을 뿐인데, 그 안에서는 무슨 일이 일어날까?”

개발을 시작하면 우리는 보통 IDE(통합개발환경)에서 코드를 작성하고, 저장하고, 실행 버튼을 누릅니다. 하지만 우리가 작성한 그 코드가 어떻게 실제로 프로그램으로 동작하는 걸까요? 이 글에서는 그 과정의 이면을 들여다보며, 특히 Java 언어를 중심으로 JVM 내부의 세계와 메모리의 구체적인 동작 방식을 이야기해보려 합니다.


1. Java 코드가 실행되기까지

🧾 Step 1. 소스코드 작성 (.java)

우리는 보통 이렇게 코드를 작성합니다:

public class Hello {
    public static void main(String[] args) {
        System.out.println("Hello, world!");
    }
}

이 코드는 .java 확장자를 가진 소스 코드 파일입니다. 하지만 이 파일은 CPU가 직접 이해하지 못합니다. 우리는 컴파일이라는 과정을 거쳐야 합니다.


⚙️ Step 2. 컴파일 → 바이트코드 (.class)

Java 컴파일러(javac)는 이 .java 파일을 읽어 들여 바이트코드(Bytecode) 로 변환합니다.

javac Hello.java

결과로 Hello.class라는 파일이 생성되며, 이 파일은 JVM만 이해할 수 있는 중간 언어입니다.


🔥 Step 3. JVM에서 실행

바이트코드는 JVM(Java Virtual Machine)에 의해 해석되어 실행됩니다.

java Hello

실행하면 JVM이 해당 .class 파일을 로딩하고, 내부적으로 메모리를 할당하고, 클래스 로딩을 수행하며, 결국 main() 메서드를 찾아 실행하게 됩니다.


2. JVM의 구조: 내부는 어떻게 생겼을까?

JVM은 단순한 인터프리터가 아닙니다. 그 안에는 아주 복잡하고 정교한 구조가 존재하죠. 핵심 구성 요소는 다음과 같습니다:

+-----------------------------+
|    Class Loader Subsystem   |
+-----------------------------+
|        Runtime Data Area     |
|  - Method Area               |
|  - Heap                     |
|  - Java Stack               |
|  - PC Register              |
|  - Native Method Stack      |
+-----------------------------+
|        Execution Engine      |
|  - Interpreter               |
|  - JIT Compiler              |
+-----------------------------+

3. 메모리 구조: Runtime Data Area

JVM이 실행되면 다음과 같은 메모리 영역들이 생성됩니다.

🧠 1) 메서드 영역 (Method Area)

  • 클래스 수준의 정보가 저장됨 (필드, 메서드, static 변수 등)
  • 모든 스레드가 공유
  • static 변수나 클래스 메타데이터가 여기 저장됨

🐘 2) 힙 영역 (Heap)

  • new 키워드로 생성한 객체들이 저장됨
  • GC(Garbage Collector)의 대상
  • 모든 스레드가 공유
Person p = new Person(); // 힙에 저장

🧵 3) 스택 영역 (Java Stack)

  • 스레드마다 하나씩 존재
  • 메서드 호출 시 생성되는 프레임이 쌓임
  • 지역변수, 매개변수가 저장됨
  • 메서드가 끝나면 해당 프레임은 pop됨

⏱️ 4) PC 레지스터 (Program Counter Register)

  • 현재 스레드가 실행 중인 바이트코드 명령의 주소를 가리킴

🛠️ 5) 네이티브 메서드 스택

  • C/C++ 등의 native 메서드 호출을 위한 스택

4. 실행 엔진: 코드를 실제로 돌리는 힘

1️⃣ 인터프리터 (Interpreter)

  • 바이트코드를 한 줄씩 읽고 해석
  • 빠른 시작이 장점이지만 반복된 실행에서 느림

2️⃣ JIT 컴파일러 (Just-In-Time Compiler)

  • 자주 실행되는 바이트코드를 네이티브 코드로 변환하여 캐싱
  • 실행 속도 향상
  • JVM이 실행 중인 동안 실시간으로 수행됨

5. GC (Garbage Collection): 힙 메모리의 청소부

Java는 메모리 관리를 자동으로 해줍니다. 그 중심에는 GC(Garbage Collector) 가 있죠.

  • 더 이상 참조되지 않는 객체들을 주기적으로 탐색해 제거
  • 다양한 알고리즘 존재 (Mark & Sweep, Generational GC 등)
  • Java 9 이후 G1 GC가 기본 채택됨

6. 스레드와 동시성

JVM은 멀티스레딩을 지원합니다. 각 스레드는 독립적인 스택을 가지며, 힙 영역을 공유합니다. 이를 통해 동시성과 병렬 처리가 가능하지만, 동기화 문제나 데드락 등의 이슈도 함께 생길 수 있죠.

synchronized(obj) {
    // 한 번에 한 스레드만 접근 가능
}

7. 실행이 끝나면?

JVM이 모든 작업을 마치면, 스택 영역과 힙 영역은 GC 또는 JVM 종료와 함께 정리됩니다. 우리가 쓴 System.exit() 나 main() 종료는 곧 프로그램의 생명 주기의 끝을 의미합니다.


마무리하며: 코드를 안다는 것의 의미

많은 초보 개발자들은 “코드를 잘 짜는 것”을 문법이나 라이브러리의 사용법으로 이해합니다. 그러나 진짜 실력은 코드가 어떻게 실행되는지를 이해하는 것에서 나옵니다.

  • 클래스가 언제 메모리에 올라가는지
  • 객체는 어디에 저장되는지
  • GC가 어떤 기준으로 동작하는지
  • 성능에 영향을 미치는 메모리 구조는 어떤지

이런 것들을 이해하고 나면, 코드가 단순히 “돌아가기만” 하는 것이 아니라, 어떻게 잘 돌아가게 할 것인가에 대한 통찰을 얻을 수 있습니다.


💡 “눈에 보이지 않는 실행 흐름까지 이해할 때, 우리는 진짜 개발자가 된다.”

VO와 DTO 개념 심층 가이드
VO와 DTO 개념 심층 가이드
2025.09.02.
Web
Server
데이터 구조 정의 및 전달 방식
🔒 Web Locks API 완벽 가이드: 브라우저 다중 탭 동시성 제어와 리더 선출
🔒 Web Locks API 완벽 가이드: 브라우저 다중 탭 동시성 제어와 리더 선출
2026.10.17.
Web
탭이 10개 열려도 데이터 꼬임 없는 브라우저 락
🔊 Web Audio API 완벽 가이드
🔊 Web Audio API 완벽 가이드
2026.10.16.
Web
브라우저에서 직접 사운드를 조작하다
📡 Web Bluetooth API 완벽 가이드: 브라우저에서 하드웨어를 직접 제어하는 방법
📡 Web Bluetooth API 완벽 가이드: 브라우저에서 하드웨어를 직접 제어하는 방법
2026.10.15.
Web
브라우저에서 블루투스 기기와 통신하기

Thank You for Visiting My Blog, Have a Good Day 🌿

© 2024 Developer LIM.