Skip to content

iq-dev-lab/memory-management-compared

Repository files navigation

🧬 Memory Management Compared

"한 런타임의 GC를 아는 것과, 모든 메모리 관리가 '언제 회수하고 누가 비용을 치르나'에 다르게 답한 것임을 아는 것은 다르다"


"안 쓰는 메모리를 언제·어떻게 회수하나 — 한 질문, 세 가지 답, 여섯 런타임."

추적 GC(JVM·V8·Go·ART) · 참조 카운팅(Swift ARC) · 소유권(Rust)을 한 자리에 놓고 "무엇이 갈렸는가, 왜 갈렸는가" 를 같은 축으로 비교합니다


GitHub Synthesis Runtimes Models Docs Words License


🎯 이 레포에 대하여

메모리 관리 자료는 보통 한 런타임 안에서만 깊어집니다. JVM GC 문서는 G1을 끝까지 파고, Swift ARC 문서는 retain/release만 다룹니다. 그래서 한 언어의 GC를 잘 아는 사람도 "GC와 ARC와 소유권이 같은 문제의 다른 답" 이라는 그림은 잘 그리지 못합니다.

일반 자료 이 레포
"G1은 영역(Region) 기반 GC다" JVM G1·ZGC·Go·V8 Orinoco·ART Concurrent Copying을 같은 축(STW·처리량·메모리 헤드룸)에서 비교
"Swift는 ARC를 쓴다" ARC가 컴파일러가 retain/release를 삽입하는 RC이며, GC와 정반대 트레이드오프(즉시 해제 vs 카운팅 오버헤드 vs 순환 누수)를 가짐을 나란히 본다
"Rust는 GC가 없어서 빠르다" "런타임 0"의 진짜 의미 — 비용이 컴파일 타임 복잡도와 표현 제약으로 옮겨갔을 뿐 사라지지 않았음
"순환 참조는 메모리 누수다" 같은 순환 A→B→A가 GC에선 회수되고 ARC/Rc에선 누수되는 이유, 각 모델의 약점 위치가 다른 메커니즘
"GC pause를 줄여야 한다" 동시 GC의 보편 도구 — 삼색 표시·쓰기 배리어가 JVM·Go·ART에서 같은 알고리즘을 다르게 튜닝한 모습
"Rust는 어렵고 GC는 편하다" 워크로드(서버·모바일·시스템)가 어떻게 모델 선택을 강제했는지, 정치가 아닌 공학적 논리
런타임 한 개만 설명 동일 데이터 구조를 6런타임으로 측정 — 같은 누수, 다른 약점

선행 학습 권장: 각 런타임의 GC/메모리 모델 레포 6개. 이 레포는 그것들을 횡단으로 묶는 수렴점입니다. 아래 🔗 레포 연결 참고.


🚀 빠른 시작

각 챕터의 첫 문서부터 바로 학습을 시작하세요!

Chapter 1 Chapter 2 Chapter 3 Chapter 4 Chapter 5 Chapter 6 Chapter 7


📊 레포 통계

항목 수치
챕터 7
문서 36
총 분량 ~80,000 단어 / ~650 KB
평균 분량 문서당 ~2,200 단어
비교 대상 런타임 6 — JVM · V8 · Go · ART · Swift · Rust
모델 3 — 추적 GC · 참조 카운팅(ARC) · 소유권

📚 전체 학습 지도

💡 각 섹션을 클릭하면 상세 문서 목록이 펼쳐집니다


🔹 Chapter 1: 메모리 관리의 근본 문제

핵심 질문: 안 쓰는 메모리를 어떻게 안전하게 회수하나 — 그리고 그 비용은 누가 치르나?

두 가지 질문, 수동 관리의 함정, 메모리 계층, 세 접근의 개요, 비교 프레임까지 (5개 문서)
문서 다루는 내용
01. 두 가지 질문 ① 언제 회수가 안전한가(도달 불가)와 ② 누가 비용을 치르나(프로그래머·런타임·컴파일러) — 모든 메모리 전략을 이 두 질문으로 환원하는 프레임
02. 수동 관리의 문제 C/C++의 use-after-free·이중해제·누수 사례, 왜 자동화가 필요한가, 그러나 자동화의 비용은 어디로 가는가
03. 메모리 계층의 그림자 회수 비용이 캐시·대역폭·NUMA와 얽히는 지점, 모든 GC 비용의 바닥(computer-architecture-deep-dive 연결)
04. 세 가지 접근의 개요 추적 GC·참조 카운팅·소유권이 각자 어디서·언제·어떻게 회수하는지를 한 그림으로, 본 레포의 전체 지도
05. 비교 프레임 평가 축 5개(지연·처리량·메모리 오버헤드·결정성·복잡도)를 정의, 모든 챕터에서 같은 축으로 모델을 평가

🔹 Chapter 2: 추적 GC — "도달 가능성"

핵심 질문: 루트에서 도달할 수 없는 객체를 찾아 회수한다는 발상은 어떻게 알고리즘이 되는가?

추적 원리, 표시-쓸기·복사·압축, 세대 가설, JVM·V8·Go GC까지 (6개 문서)
문서 다루는 내용
01. 도달 가능성 루트 집합에서 시작해 참조 그래프를 순회, 도달 가능한 객체만 살리고 나머지를 회수하는 추적 GC의 공리
02. 표시-쓸기·복사·압축 세 기본 알고리즘의 트레이드오프, 단편화 문제가 압축을 강제하는 이유, 각 알고리즘의 비용 위치
03. 세대 가설 "대부분 객체는 일찍 죽는다"는 경험적 가설, young/old 분리가 가져온 처리량 혁명, JVM·V8·ART의 공통 토대
04. JVM GC — G1과 ZGC 영역(Region) 기반 G1의 점진적 압축, 컬러 포인터 기반 ZGC의 sub-ms STW 목표 (jvm-deep-dive 연결)
05. V8 Orinoco Scavenge(young) + Mark-Compact(old), 병렬·동시·증분의 3계층 (v8-engine-deep-dive 연결)
06. Go GC 세대 없는 동시 삼색 표시, 짧은 STW 목표(<1ms)와 그 대가(높은 메모리 헤드룸) (go-deep-dive 연결)

🔹 Chapter 3: 동시·증분 GC — STW 줄이기

핵심 질문: "잠시 멈춤" 없이 살아있는 객체와 죽은 객체를 어떻게 정확히 구분하는가?

STW의 비용, 삼색 표시, 쓰기 배리어, ART, 동시 GC 비교까지 (5개 문서)
문서 다루는 내용
01. STW 문제 Stop-The-World가 지연·jank·tail latency를 만드는 이유, 서버 SLO와 모바일 60fps에서 STW가 왜 1순위 문제인가
02. 삼색 표시 white/grey/black 분류, 동시 표시가 정확성을 유지하기 위한 불변식, 모든 동시 GC의 공통 언어
03. 쓰기 배리어 동시 표시 중 *변이(mutation)*가 일어날 때 정확성을 지키는 컴파일러 삽입 코드, SATB와 incremental update의 두 흐름
04. ART GC Concurrent Copying으로 모바일 jank를 0에 가깝게 — Android의 60fps 제약이 어떻게 GC 설계를 결정했는가 (android-runtime-deep-dive 연결)
05. 동시 GC 비교 JVM ZGC · Go GC · ART CC의 STW 목표 vs 처리량 vs 메모리 오버헤드를 같은 표에 — 같은 알고리즘, 다른 튜닝

🔹 Chapter 4: 참조 카운팅 — Swift ARC

핵심 질문: "참조 수가 0이 되면 즉시 해제"라는 단순한 규칙은 왜 GC와 정반대 비용 구조를 만드는가?

RC 원리, ARC의 컴파일러 삽입, GC와의 정면 비교, 순환 약점, 비용 측정까지 (5개 문서)
문서 다루는 내용
01. 참조 카운팅 원리 참조 수를 세어 0이면 즉시 회수하는 결정적 모델, GC 스레드도 STW도 없는 대신 분산된 카운팅 비용
02. ARC — 컴파일러가 삽입하는 RC Swift 컴파일러가 retain/release를 결정론적으로 삽입하는 메커니즘 (swift-deep-dive 연결), Objective-C MRC와의 비교
03. GC vs ARC 결정성·즉시 회수 vs 카운팅 오버헤드·순환 약점을 같은 축에서 — Bacon의 "A Unified Theory of Garbage Collection"이 말하는 쌍대성
04. 순환 참조의 약점 A→B→A가 RC에서 근본적으로 회수 불가인 이유, weak/unowned의 진짜 의미와 수동 해결의 비용
05. ARC의 진짜 비용 retain/release 원자적 연산의 빈도와 캐시 영향, 컴파일러 최적화(__owned, retain elision)가 줄여주는 부분과 그렇지 못한 부분

🔹 Chapter 5: 소유권 — Rust (런타임 0)

핵심 질문: 런타임 메모리 관리 비용을 0으로 만든다는 약속의 대가는 무엇인가?

소유권 모델, RAII, 빌림 검사, Rc/Arc 선택지, 소유권의 비용까지 (5개 문서)
문서 다루는 내용
01. 소유권 모델 컴파일 타임에 수명 결정 — GC도 RC도 없이 안전을 보장하는 발상의 진짜 의미 (rust-deep-dive 연결)
02. RAII와 drop 스코프 종료 시 결정적 해제, C++의 RAII를 언어 수준 보증으로 끌어올린 Rust의 변형
03. 빌림 검사 UAF·이중해제·data race를 컴파일 타임에 제거하는 메커니즘, 표현 제약과의 트레이드오프
04. Rc와 Arc — 선택적 RC Rust도 필요시 참조 카운팅을 옵트인으로 제공, ARC와 달리 모든 객체가 아니라 선택한 객체만 RC
05. 소유권의 비용 런타임 0의 대가 — 학습 난이도·표현 제약·컴파일 시간, "fighting the borrow checker" 현상의 정체

🔹 Chapter 6: 같은 문제, 다른 약점

핵심 질문: 같은 누수 시나리오가 각 모델에서 어떻게 다르게 발현하는가?

순환 참조, 메모리 누수, 지연·처리량·오버헤드·결정성, 6런타임 측정까지 (6개 문서)
문서 다루는 내용
01. 순환 참조 GC: 도달 불가면 회수 (강점) · ARC: 카운트 0 안 됨 (누수) · Rust Rc: 동일 문제, Weak 필요 — 같은 그래프, 세 운명
02. 메모리 누수의 형태들 GC의 논리적 누수(살아있는 참조), ARC의 순환 누수, Rust의 Rc 순환과 leak() — 누수의 위치가 다르다
03. 지연 vs 처리량 GC의 집중된 STW · ARC의 분산 카운팅 비용 · Rust의 예측 가능한 drop — tail latency가 만들어지는 방식의 차이
04. 메모리 오버헤드 GC의 여유 힙(헤드룸) · ARC의 카운트 필드 · Rust의 (거의)0 — 같은 데이터 구조의 실측 메모리
05. 결정성 "언제 해제되는가"의 예측 가능성 — GC의 비결정성(finalizer 위험), ARC/Rust의 결정성, finalizer vs Drop의 의미론 차이
06. 같은 프로그램, 6런타임 측정 동일 객체 그래프(트리·DAG·순환)를 6런타임으로 구현, 메모리 피크·해제 지연·STW를 한 표에 정리

🔹 Chapter 7: 트레이드오프 종합

핵심 질문: 왜 서버는 GC, 모바일은 ARC, 시스템은 소유권으로 갈렸는가 — 그리고 이게 우연인가?

평가 축 종합, 워크로드의 강제, 선택의 논리, 메모리 관리 지형도까지 (4개 문서)
문서 다루는 내용
01. 평가 축 종합 Chapter 1에서 정의한 5축으로 6런타임을 한 표로 — 처음으로 모든 모델이 동일 단위로 비교됨
02. 왜 갈렸나 — 워크로드의 강제 서버(처리량 최우선) → GC, 모바일(저지연·메모리 제약) → ARC/저지연 GC, 시스템(예측성·런타임 0) → 소유권 — 정치가 아닌 공학적 강제
03. 선택의 논리 새 프로젝트의 메모리 전략을 결정하는 의사결정 트리, 워크로드 → 제약 → 모델의 흐름을 체크리스트로
04. 종합 — 메모리 관리 지형도 모든 챕터의 결론을 한 장의 지형도로, 새 런타임(예: 비RC ARC 변형, hybrid GC+RC)을 만나도 이 프레임으로 분류 가능

🗺️ 목적별 학습 경로

🟢 "GC와 ARC와 Rust가 같은 문제의 다른 답"이라는 핵심만 빠르게 (1주)

핵심 4문서 — 한 질문, 세 답, 한 지형도

Ch1-04  세 가지 접근의 개요
Ch4-03  GC vs ARC (Bacon의 쌍대성)
Ch6-01  순환 참조 — 같은 문제, 세 운명
Ch7-04  메모리 관리 지형도
🔵 메모리 관리의 횡단 그림을 끝까지 (7주)
Week 1  Chapter 1 전체 — 근본 문제와 비교 프레임
Week 2  Chapter 2 전체 — 추적 GC (JVM·V8·Go)
Week 3  Chapter 3 전체 — 동시 GC (삼색·쓰기 배리어·ART)
Week 4  Chapter 4 전체 — Swift ARC와 RC 모델
Week 5  Chapter 5 전체 — Rust 소유권
Week 6  Chapter 6 전체 — 같은 문제, 다른 약점 + 6런타임 측정
Week 7  Chapter 7 전체 — 트레이드오프 종합과 선택 논리
🔴 런타임 선택 의사결정자(아키텍트·CTO) 집중 코스
의사결정에 필요한 최소 경로

Step 1  Ch1-01, 05  두 질문 + 5축 프레임
Step 2  Ch4-03      GC vs ARC 정면 비교
Step 3  Ch5-01, 05  소유권 모델과 그 비용
Step 4  Ch6-03, 04  지연·처리량·메모리 오버헤드 실측
Step 5  Ch7-02, 03  왜 갈렸나 + 선택 논리

각 문서의 "📊 측정" 섹션에서 6런타임 정량 비교를 확인하세요.

📖 각 문서 구성 방식

모든 문서는 동일한 구조로 작성됩니다. 비교가 핵심이므로 🔬·📊에서 항상 여러 모델을 나란히 다룹니다.

섹션 설명
🎯 핵심 질문 이 문서를 읽고 나면 답할 수 있는 질문
🔍 왜 이게 존재하는가 풀려는 문제와 설계 배경 — 항상 공통 문제에서 출발
😱 흔한 오해 또는 잘못된 사용 Before — "한 모델만 알고 다른 모델을 오해"하는 패턴
올바른 이해와 사용 After — 모델들을 나란히 놓고 본 후의 정확한 그림
🔬 내부 동작 원리 알고리즘·자료구조 + 여러 런타임의 변형 비교 (예: 삼색 표시를 JVM·Go·ART가 어떻게 다르게 구현하나)
💻 실전 실험 같은 객체 그래프를 2개 이상 런타임으로 구현, 차이를 눈으로
📊 측정 메모리 피크·STW·해제 지연·throughput을 같은 표로 — 가능한 한 6런타임 모두
🤔 트레이드오프 이 모델의 장단점, 다른 모델이 더 나은 시나리오
📌 핵심 정리 한 화면 요약
🤔 생각해볼 문제 횡단 사고를 강제하는 질문 + 해설

🔬 검증 환경

polyglot. 같은 객체 그래프를 6런타임으로 측정하는 것이 이 레포의 정체성입니다.

FROM ubuntu:24.04

# JVM (HotSpot 21)
RUN apt-get update && apt-get install -y openjdk-21-jdk

# Go
RUN apt-get install -y golang-go

# Node (V8)
RUN apt-get install -y nodejs npm

# Rust
RUN curl https://sh.rustup.rs -sSf | sh -s -- -y

# Swift — 별도 이미지 권장 (swift:6)
# Android/ART — 별도 SDK (android-runtime-deep-dive 참고)
# 핵심 검증 1 — 같은 메모리 패턴을 6런타임으로 비교
# 패턴 예: "10만 개 객체 할당 → 절반 unreachable → 회수 관찰"

# 추적 GC 관찰
java -Xlog:gc*,gc+heap=debug demo.java          # JVM GC 로그·STW·세대별 회수
GODEBUG=gctrace=1 ./go-demo                     # Go GC·STW·heap 추적
node --trace-gc --trace-gc-verbose demo.js      # V8 GC

# 핵심 검증 2 — ARC 트래픽 관찰 (Swift)
swiftc -emit-sil demo.swift | grep -E 'retain|release'   # 컴파일러 삽입 카운팅
# Xcode Instruments — Allocations · Leaks · ARC traffic

# 핵심 검증 3 — Rust (런타임 0)
cargo build                # drop 시점이 컴파일 타임 결정
# 누수 가능 경로: Rc<RefCell> 순환만 (Weak 미사용 시) 또는 명시적 Box::leak

# 핵심 검증 4 — 순환 참조의 운명 비교
#   JVM/Go/JS:  A→B→A 순환이어도 GC가 회수 (도달 불가면)            ✓
#   Swift ARC:  강한 순환 → 누수, weak/unowned 필요                  ✗
#   Rust Rc:    Rc 순환 → 누수, Weak 필요                            ✗
#   → GC의 강점이 RC/소유권의 약점, 정확히 같은 입력에 다른 결과

# 측정 — 동일 객체 그래프의:
#   메모리 피크 (RSS, heap)
#   해제 지연 (객체 도달 불가 → 메모리 해제까지)
#   STW 분포 (p50, p99, max)
#   할당/해제 throughput
# 를 6런타임에서 같은 단위로 비교

🔗 레포 연결

⬆️ 선행 (이 비교의 입력 — 각 런타임의 메모리 모델을 깊게)
  jvm-deep-dive                    → JVM GC (G1·ZGC) 내부
  v8-engine-deep-dive              → V8 Orinoco (Scavenge + Mark-Compact)
  go-deep-dive                     → Go GC (동시 삼색, 세대 없음)
  android-runtime-deep-dive        → ART Concurrent Copying
  swift-deep-dive                  → Swift ARC (컴파일러 삽입 RC)
  rust-deep-dive                   → Rust 소유권·빌림 검사

🤝 시너지 (메모리 관리의 *바닥*과 *수단*)
  computer-architecture-deep-dive  → 메모리 계층·캐시·NUMA (모든 GC 비용의 바닥)
  compiler-deep-dive               → 컴파일러가 retain/release·drop·write barrier를 삽입

🧬 본질
  이 레포 = 6개 런타임의 메모리 전략이 수렴하는 지점
  한 런타임 깊이 → 횡단 비교 → 새 런타임을 만나도 이 프레임으로 분류

🙏 Reference


⭐️ 도움이 되셨다면 Star를 눌러주세요!

Made with ❤️ by Dev Book Lab


"한 질문, 세 답, 여섯 런타임 — 메모리 관리는 정치가 아니라 트레이드오프다"

About

한 런타임의 GC를 아는 것과, 모든 메모리 관리가 '언제 회수하고 누가 비용을 치르나'에 다르게 답한 것임을 아는 것은 다르다

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors