콘텐츠로 바로가기

Runtime Systems & Memory Management

프로그램 실행을 관리하는 가상 머신, 인터프리터 루프, 그리고 자동 메모리 관리(GC) 알고리즘의 물리적 거동을 다루는 학습 노드입니다.

Article
M

Me

hyunyoun's Blog

programming-languages-compilersprogramming-languagescompilersruntime-systemsmemory-managementlanguages-compilerslearningallocation-strategies9 min read

1. Overview

런타임 시스템 및 메모리 관리 최적화(Runtime Systems & Memory Management Optimization, RMO)는 프로그램이 디스크의 정적인 바이너리에서 메모리에 적재된 프로세스로 실행된 뒤 일어나는 동적 동작과 런타임 환경(Runtime Environment)의 내부 메커니즘을 다룹니다.

C/C++처럼 컴파일러가 대부분의 실행 준비를 미리 끝내는 언어와 달리, Java, Python, JavaScript 같은 현대 언어들은 가상 머신(VM)과 런타임 엔진이 실행 과정에 계속 관여합니다. 학습자는 바이트코드(Bytecode)를 한 줄씩 읽어 들이는 인터프리터(Interpreter)의 루프를 이해하고, 자주 쓰이는 코드를 런타임에 기계어로 번역하는 JIT(Just-In-Time) 컴파일러의 동작을 배웁니다. 또한 수백만 개의 객체가 생성되고 버려지는 힙(Heap) 메모리 공간에서, 더 이상 쓰이지 않는 객체(Garbage)를 찾아 회수하는 GC(Garbage Collection)의 세대별(Generational) 수거 방식과 Stop-the-World 지연(Latency) 통제 기술을 살펴봅니다.

2. Scope & Boundaries

In-Scope

  • 가상 머신과 실행 엔진 (Virtual Execution): 스택 기반 VM(JVM) vs 레지스터 기반 VM(Dalvik, V8), 바이트코드 포맷, 인터프리터 루프(Dispatch Loop) 오버헤드.
  • 동적 컴파일링 (Dynamic Compilation): JIT 컴파일러의 프로파일링(Profiling) 기반 핫스팟(Hot Spot) 최적화, 온스택 리플레이스먼트(OSR, On-Stack Replacement), 인라인 캐시(Inline Cache).
  • 자동 메모리 수거 기초 (GC Foundations): 도달 가능성(Reachability) 분석, 루트 셋(Root Set), 참조 카운팅(Reference Counting), 순환 참조(Circular Reference) 파괴.
  • 고급 가비지 컬렉션 물리 (Advanced GC Mechanics): Mark-and-Sweep, Mark-and-Compact, 세대별 GC(Young/Old Generation, Eden/Survivor), 무정지(Concurrent) GC의 쓰기 장벽(Write Barrier).

Out-of-Scope

  • 운영체제 레벨의 페이지 교체 알고리즘: 페이징(Paging), 세그먼테이션(Segmentation), TLB(Translation Lookaside Buffer) 미스 처리 → 03. Operating Systems 영역으로 위임.
  • 정적 컴파일 파이프라인: 구문 분석(Parsing)부터 LLVM IR을 통한 사전(AOT) 최적화 단계 → 05-02. Compiler Design 영역으로 위임.

Boundaries

  • RMO vs. LPNS (05-04): LPNS가 C/Rust처럼 '개발자가 직접' 힙 메모리의 수명을 통제하고 하드웨어에 밀착하는 기술이라면, RMO는 '시스템(VM/GC)이 대신' 메모리 수명을 추적하고 코드를 런타임에 재단해 주는 자동화된 환경의 물리적 오버헤드와 튜닝 포인트를 다룹니다.

3. Counterexample

  • GC를 과신한 메모리 누수 간과: "Java나 Python은 가비지 컬렉터가 있으니 메모리 누수(Memory Leak)가 없다"고 단정하는 사례. 더 이상 사용하지 않는 거대한 객체 리스트를 전역 변수(Static)나 캐시용 맵(Map)에 계속 담아두면, GC는 이를 '여전히 사용 중인 도달 가능한(Reachable) 객체'로 판정하여 회수하지 않고 결국 OutOfMemoryError(OOM)를 일으키는 논리적 누수 현상을 파악해야 합니다.
  • 단순 벤치마크 루프를 통한 JIT 오판: "for문을 10번 돌려봤더니 Java가 C보다 훨씬 느리다"고 단정하는 것. JIT 컴파일러는 초반 실행 시 인터프리터로 코드를 분석(Warm-up)하며 프로파일링 데이터를 쌓다가, 특정 횟수 이상(예: 1만 번) 루프가 반복되면 C언어에 가까운 기계어를 생성하는 지연 최적화(Lazy Optimization) 특성을 가지므로, 런타임 특성을 무시한 정적 벤치마크는 무의미합니다.

4. Prerequisites

  • 컴파일러 설계 (Basic): JIT 엔진을 이해하려면 런타임에 수행되는 코드 제너레이션과 레지스터 할당 원리를 알아야 합니다. (05-02. CDI)
  • 메모리 계층 구조 (Recommended): GC가 객체를 압축(Compaction)할 때 CPU 캐시 지역성(Cache Locality)이 회복되는 원리를 이해하려면 컴퓨터 아키텍처 기초가 필요합니다. (02. Computer Architecture)

5. Learning Map

Sequence Core Cluster Objective & Description Evidence (BoK)
1 Interpreter & VM Physics 바이트코드를 소프트웨어 가상 CPU(스택/레지스터 기반)가 읽고 분기하는 루프의 한계를 이해합니다. P1/Runtimes
2 Just-In-Time Compilation 반복 실행되는 핫스팟 코드를 런타임에 기계어로 교체해 인터프리터의 한계를 보완하는 JIT를 익힙니다. P1/Runtimes
3 Garbage Collection Math 도달 불가능한 객체를 찾아내고 힙의 파편화(Fragmentation)를 줄이는 GC 기초를 배웁니다. P1/Runtimes
4 Generational & Low-Latency GC 수명이 짧은 객체와 긴 객체를 분리(세대별)하고, 정지 시간(STW)을 줄이는 최신 동시성 GC를 튜닝합니다. Industry

6. Learning Topics

Basic

Core Topic 01: 실행 엔진과 가상 머신 아키텍처 (VM Execution Models)

  • Why to Learn: 하드웨어 CPU마다 컴파일을 따로 하지 않고 'Write Once, Run Anywhere'를 달성하는 이면에 존재하는 소프트웨어 번역 루프의 오버헤드를 체감하기 위함입니다.
  • What to Learn:
    • Concepts: 가상 머신(Virtual Machine), 바이트코드(Bytecode), 명령어 디스패치(Instruction Dispatch).
    • Skills: 스택 기반 VM(Stack-based, 피연산자를 스택에 푸시/팝) vs 레지스터 기반 VM(Register-based, 가상 레지스터 배열 직접 접근) 물리 동작 비교.
    • Tools: 바이트코드 디스어셈블러(Java javap, Python dis).
    • Trade-offs: 스택 머신의 컴파일러 제작 용이성과 컴팩트한 바이트코드 크기 vs 레지스터 머신의 적은 명령어 개수와 빠른 디스패치 루프 속도 간의 타협.
  • How to Learn:
    • 1단계: C=A+BC = A + B 라는 연산을 스택 머신용 명령어(ILOAD A, ILOAD B, IADD, ISTORE C)와 레지스터 머신용 명령어(ADD R3, R1, R2)로 변환해 메모리 접근 횟수를 비교합니다.
    • 2단계: 거대한 switch-case 문으로 바이트코드를 읽어 들이는 인터프리터 코드를 작성해 보고, 매번 분기문에서 발생하는 CPU 파이프라인 플러시(Flush) 패널티를 인식합니다.
  • Implement: 10여 개의 커스텀 바이트코드(PUSH, POP, ADD, JMP)를 받아 스택 메모리를 갱신하며 결과값을 출력하는 초소형 가상 머신(VM) 엔진 C 코드 구현.

Core Topic 02: JIT 컴파일러와 동적 최적화 (Dynamic JIT & Profiling)

  • Why to Learn: 처음에는 느리게 실행되던 코드가 몇 초 뒤 빠르게 가속되는 현대 브라우저(V8)나 서버(JVM)의 동적 기계어 생성 방식을 이해하기 위해서입니다.
  • What to Learn:
    • Concepts: JIT(Just-In-Time) 컴파일, AOT(Ahead-Of-Time), 웜업(Warm-up), 핫스팟(Hotspot) 프로파일링.
    • Skills: 온스택 리플레이스먼트(On-Stack Replacement, OSR: 실행 중인 루프 중간에 기계어 실행으로 전환), 다형성 인라인 캐시(Polymorphic Inline Cache, PIC)를 통한 동적 타입 탐색 오버헤드 감소.
    • Tools: JVM 티어드 컴파일레이션(Tiered Compilation) 로그 분석 도구.
    • Trade-offs: 즉시 시작 가능하나 실행이 느린 인터프리터 vs 실행은 빠르지만 컴파일 비용 때문에 시작이 느린 JIT 컴파일러의 단점을 상호 보완하는 다단계(Tiered) 실행 체제.
  • How to Learn:
    • 1단계: 동적 타입 언어에서 obj.method()를 호출할 때마다 프로토타입 체인을 탐색하는 비용을, JIT가 "이전에 호출된 객체 타입이 A였으니 이번에도 A일 것이다"라고 추측해 조건문 하나(Inline Cache)로 캐싱하는 과정을 도식화합니다.
    • 2단계: 최적화가 잘못되었다는 것(Deoptimization)이 판명 났을 때 기계어 코드 실행을 즉시 멈추고 안전하게 인터프리터로 롤백하는 가드(Guard) 조건을 연구합니다.
  • Implement: 특정 함수가 10회 이상 호출될 때마다 호출 카운트를 올리고, 임계치 도달 시 함수 포인터를 '빠른 모의 함수'로 교체하는 단순 핫스팟 JIT 시뮬레이터.

Practical

Core Topic 03: 가비지 컬렉션의 추적과 회수 물리 (GC Foundations)

  • Why to Learn: mallocfree를 직접 관리하는 부담을 줄여 주는 자동 수거기가 어떤 알고리즘으로 살아있는 객체와 회수 대상 객체를 구분하는지 알아야 힙(Heap) 튜닝이 가능해지기 때문입니다.
  • What to Learn:
    • Concepts: 루트 셋(Root Set: 전역 변수, 스택 지역 변수), 도달 가능성(Reachability), 파편화(Fragmentation).
    • Skills: 참조 카운팅(Reference Counting)과 순환 참조(A \rightarrow B \rightarrow A)의 한계 증명, Tracing GC(Mark-and-Sweep)의 재귀적 마킹 흐름, 복사(Copying) GC의 From/To-Space 분할 압축 기법.
    • Tools: 힙 덤프(Heap Dump) 분석기(MAT).
    • Trade-offs: 객체가 소멸 즉시 메모리를 회수하는 참조 카운팅의 낮은 최대 지연 시간 vs 참조 카운터 증감 시 발생하는 캐시 라인(Cache Line) 무효화 및 순환 참조 누수라는 한계.
  • How to Learn:
    • 1단계: 10개의 객체가 서로 얽힌 객체 그래프를 그리고, 스택에 연결된 루트 셋에서 출발해 도달 불가능한 '섬(Island of Garbage)' 객체들을 Mark-and-Sweep으로 찾아내어 비트맵을 0으로 지우는 훈련을 합니다.
    • 2단계: 메모리 파편화로 인해 10MB 여유 공간이 있음에도 2MB짜리 배열을 할당하지 못하는 상황을 막기 위해, 살아남은 객체들을 메모리 한쪽으로 촘촘하게 복사해 넣는(Compaction) 비용 공식을 세웁니다.
  • Implement: struct Object { int mark; ... } 기반의 가상 힙 리스트를 순회하며 루트 노드부터 재귀적으로 mark=1을 찍은 뒤, mark=0인 객체들의 메모리를 전부 해제하는 기초 마크-앤-스위프(Mark & Sweep) 엔진.

Advanced

Core Topic 04: 세대별 힙과 저지연 무정지 GC (Generational & Low-Latency GC)

  • Why to Learn: 수백 GB의 대용량 메모리를 쓰는 데이터베이스나 초저지연 거래 시스템에서, 프로그램이 몇 초씩 멈추는 Stop-The-World(STW) 현상을 수 밀리초 단위로 억제하기 위함입니다.
  • What to Learn:
    • Concepts: 약한 세대 가설(Weak Generational Hypothesis), 에덴(Eden)과 서바이버(Survivor), 테뉴어드(Tenured/Old) 영역, 쓰기 장벽(Write Barrier).
    • Skills: Minor GC(Young 영역 중심 수집) vs Major GC(전체 힙 수집)의 발동 조건 제어, 동시성 마킹(Concurrent Marking) 시 애플리케이션 스레드(Mutator)가 포인터를 바꿀 때 발생하는 마킹 누락 문제(Lost Object) 해결 방식.
    • Tools: GC 로그 뷰어(GCEasy), JVM 플래그 튜닝(-XX:+UseG1GC, -Xmx).
    • Trade-offs: STW를 없애기 위해 애플리케이션 실행과 동시에 GC를 수행할 때 들어가는 추가 CPU 연산(읽기/쓰기 배리어) 오버헤드(Throughput 감소) vs STW를 1ms 이하로 줄이는 지연 시간(Latency) 통제 능력.
  • How to Learn:
    • 1단계: "새로 생성된 객체는 금방 쓰레기가 되고, 오래 살아남은 객체는 계속 살아남는다"는 세대 가설을 바탕으로, 전체 힙을 뒤지지 않고 Young 영역을 중심으로 수집해 GC 시간을 90% 단축하는 세대 분리 파티셔닝 구조를 설계합니다.
    • 2단계: GC가 객체 A를 검사 완료했는데, 동시에 실행 중인 앱 스레드가 검사 안 한 B를 A 밑으로 옮겨 B가 잘못 회수될 수 있는 상황(삼색 마킹 트리 위반)을 쓰기 장벽(Write Barrier) 코드가 어떻게 차단하는지 논리 흐름을 추적합니다.
  • Implement: 메모리 할당 속도와 객체 소멸 확률 파라미터를 입력받아, 세대별 GC 환경에서 Young 영역이 가득 찼을 때 객체들이 Survivor 공간을 오가며 Age가 증가하고 Old 영역으로 승급(Promotion)하는 과정을 모사한 시뮬레이터.

7. Terminology

Term (EN / ko, abbr) 1문장 정의 단계(기본/권장/실무/심화) 역할/맥락 관련 개념 유사/대비/함께 사용 오해 포인트 Evidence(Primary/Secondary/Industry) Flags(core/misused/legacy)
Garbage Collection 프로그램이 더 이상 사용하지 않는 메모리 자원을 자동으로 찾아내어 해제하는 런타임 메커니즘입니다. 기본 자원 관리 Heap Manual Free 단순히 '메모리 청소'로만 오해 P1:CS2023/Compilers core
Stop-the-World 가비지 컬렉션을 실행하기 위해 애플리케이션의 모든 실행 스레드를 중단시키는 런타임 정지 상태입니다. 추천 성능 지표 Latency Concurrent GC 코드가 계속 실행된다고 오해 Industry JVM Docs core
JIT Compilation 프로그램 실행 중에 바이트코드를 분석하여 실시간으로 타겟 기계어로 번역/최적화하는 기술입니다. 실무 성능 가속 Interpreter AOT 사전 컴파일과 동일시함 P1:CS2023 core
Safe Point 가비지 컬렉터가 안전하게 실행될 수 있도록 모든 스레드가 일관된 상태로 멈추는 실행 지점입니다. 실무 동기화 Context Switch Barrier 단순히 '코드 정지 지점'으로 오해 Industry Spec core

8. References

Primary References

Secondary References

  • [The Garbage Collection Handbook] Richard Jones et al. — The definitive GC authority.
  • [Virtual Machines] James Smith & Ravi Nair — Hardware/Software runtime architecture.

Industry References

  • [V8 JavaScript Engine Architecture] — Real-world high-performance runtime.
  • [HotSpot JVM Internal Wiki] — Deep dive into production JIT and GC.

9. Final Checklist

Primary Checklist

  • 참조 횟수 계산(Reference Counting) 방식이 순환 참조 상황에서 메모리 누수를 일으키는 물리적 이유를 설명 가능한가? (P1)
  • 세대별 GC에서 'Survivor' 공간이 두 개(S0, S1) 필요한 이유를 메모리 복사 관점에서 기술할 수 있는가? (P1)

Secondary Checklist

  • JIT 컴파일러가 인터프리터보다 속도는 빠르지만 초기 구동 시간(Warm-up)과 메모리 점유 면에서 불리한 이유를 인지하는가?
  • Stop-the-World 시간이 시스템의 응답 속도(Latency)와 사용자 경험에 미치는 물리적 영향력을 평가하고 있는가?

Industry Checklist

  • 서비스 환경의 힙 메모리 사용량 로그를 분석하여 Full GC 발생 빈도를 조절하기 위한 JVM 튜닝 제안이 가능한가? (SFIA)
  • 애플리케이션의 객체 할당 속도(Allocation Rate)가 GC 스레드 처리 속도를 넘어서는 물리적 위기 상황을 감지할 수 있는가?

Languages Compilers · Runtime Systems & Memory Management

3 / 4