F-lab Java 1์ฃผ์ฐจ / Phase 5 / Unit 5.3 ๋ณธ๊ฒฉ ํ์ต ์๋ฃ
9-์น์ ๋ง์คํฐ ํ๋กฌํํธ ํ์์ผ๋ก ๊น์ด ํํค์น๋ค.์ ์ ์ง์: Unit 5.2 (Heap์ ์ธ๋ ๊ตฌ์กฐ)
๋ค์ Unit: 5.4 โ GC ์ข ๋ฅ์ ์ ํ ๊ธฐ์ค์ด Unit์ ์๋ฏธ: GC ์ 4๊ฐ์ง ํต์ฌ ์๊ณ ๋ฆฌ์ฆ ๋น๊ต.
๊ฐ ์๊ณ ๋ฆฌ์ฆ์ ๋์ ์๋ฆฌ, ์ฅ๋จ์ , ์๋ฐ๊ฐ ๋ฌด์์ ์ฑํํ๋์ง.
๋ฉด์ ์์ "์ ์๋ฐ๋ Reference Counting ์ ์ฐ๋์?" ๊ฐ์ ๊น์ด ์๋ ์ง๋ฌธ ๋๋น.
ํฐ ์ฌ๋ฌด์ค์ ์ฒญ์ํ๋ 4๊ฐ์ง ๋ฐฉ๋ฒ์ ์์ํด๋ณด์ธ์.
์ฅ์ : ์ฆ๊ฐ์ , ๋ฉ์ถค ์์
๋จ์ : ์ํ ์ฐธ์กฐ ๋ฌธ์ โ A ๊ฐ B ์ฌ์ฉ, B ๊ฐ A ์ฌ์ฉ โ ๋ ๋ค ์ ๋ฒ๋ ค์ง โ
์ฅ์ : ์ํ ์ฐธ์กฐ ํด๊ฒฐ, ๋จ์
๋จ์ : STW, ๋น ์๋ฆฌ ๊ณณ๊ณณ (๋จํธํ)
์ฅ์ : ๋จํธํ ํด์
๋จ์ : ์ ๋ฆฌ ๋น์ฉ, ๊ฐ์ฒด ์ด๋
์ฅ์ : ํจ์จ์
๋จ์ : ๊ตฌ์กฐ ๋ณต์ก
โ ์ด๊ฒ 4๊ฐ์ง GC ์๊ณ ๋ฆฌ์ฆ. ์๋ฐ๋ ๋ฐฉ์ 4 (Generational) ์ฑํ.
"GC ์๊ณ ๋ฆฌ์ฆ์ '์ฐ๋ ๊ธฐ๋ฅผ ์ด๋ป๊ฒ ์๋ณํ๊ณ ์ ๊ฑฐํ ๊น' ์ 4๊ฐ์ง ๋ต์ด๋ค."
๊ฐ ์๊ณ ๋ฆฌ์ฆ์ trade-off:
๋น์ ์ ๋ฆฌ:
| ๋น์ | GC ์๊ณ ๋ฆฌ์ฆ | ์ฅ์ | ๋จ์ |
|---|---|---|---|
| ๋ฐฉ๋ฌธ์ ์นด์ดํฐ | Reference Counting | ์ฆ์, ๋ฉ์ถค X | ์ํ ์ฐธ์กฐ |
| ํฌ์คํธ์ ํ์ | Mark-Sweep | ๋จ์ | ๋จํธํ |
| ํ์ + ์ ๋ฆฌ | Mark-Sweep-Compact | ์์ถ | ์ด๋ ๋น์ฉ |
| ์ธ๋๋ณ ์ฒญ์ | Generational | ํจ์จ | ๋ณต์ก |
GC ์ ํต์ฌ ๋ฌธ์ :
"Heap ์ ์ด๋ค ๊ฐ์ฒด๊ฐ ์ฌ์ฉ ์ค ์ด๊ณ , ์ด๋ค ๊ฒ ์ฐ๋ ๊ธฐ ์ธ๊ฐ?"
์ด ์ง๋ฌธ์ ๋ตํ๋ ๋ฐฉ์์ด ์๊ณ ๋ฆฌ์ฆ ์ ์ฐจ์ด.
๊ฐ์ฅ ์ง๊ด์ ์ธ ๋ฐฉ์, 1950๋ ๋ LISP์์ ์ฒ์ ๋ฑ์ฅ.
์์ด๋์ด:
์ฅ์ :
๋ฌธ์ ๋ฐ๊ฒฌ โ ์ํ ์ฐธ์กฐ โ ๏ธ :
A โ B โ A
A ์ ์นด์ดํธ = 1 (B ๊ฐ ๊ฐ๋ฆฌํด)
B ์ ์นด์ดํธ = 1 (A ๊ฐ ๊ฐ๋ฆฌํด)
์ธ๋ถ์์ A, B ์ฌ์ฉ ์ ํด๋
์๋ก ๊ฐ๋ฆฌํค๋ ํ ์นด์ดํธ 0 ์ ๋จ
โ ๋ฉ๋ชจ๋ฆฌ ๋์ โ
์ฑํ ์ฌ๋ก:
shared_ptr)LISP ์ธ์ด์ John McCarthy ๊ฐ 1960๋ ์ ์ ์.
์์ด๋์ด:
์ฅ์ :
๋จ์ :
๋ฉ๋ชจ๋ฆฌ ๊ทธ๋ฆผ:
Before:
[A][B][C][D][E][F]
Mark: A, C, E ๊ฐ Live
After Sweep:
[A][_][C][_][E][_]
๋น์ ๋น์ ๋น์
โ ๋จํธํ
Mark-Sweep ์ ๋จํธํ๋ฅผ ํด๊ฒฐ.
์์ด๋์ด:
์ฅ์ :
๋จ์ :
๋ฉ๋ชจ๋ฆฌ ๊ทธ๋ฆผ:
Sweep ํ:
[A][_][C][_][E][_]
Compact ํ:
[A][C][E][_][_][_]
โ ๋ชจ๋ ๋น ๊ณต๊ฐ ๋ค๋ก
์ฝํ ์ธ๋ ๊ฐ์ค (Unit 5.1) ํ์ฉ.
์์ด๋์ด:
์ฅ์ :
๋จ์ :
์๋ฐ๋ Generational GC ๋ฅผ ๊ธฐ๋ณธ ์ฑํ:
์?:
1. ์ฝํ ์ธ๋ ๊ฐ์ค ์ ํต์ฐฐ ํ์ฉ
2. STW ์งง์ (Minor GC)
3. ํฐ ์ ๋ฆฌ๋ ๊ฐ๋๋ง (Major GC)
4. ํ๋ ๋ชจ๋ ์๋ฐ GC ๊ฐ ์ด ๊ธฐ๋ฐ
โ Serial, Parallel, CMS, G1, ZGC ๋ชจ๋ Generational + ์ถ๊ฐ ์ต์ ํ.
"GC ์๊ณ ๋ฆฌ์ฆ์ ์งํ = 'ํจ์จ + ์์ ' ์ ์ถ๊ตฌ."
Reference Counting์ ์ง๊ด์ฑ โ ์ํ ์ฐธ์กฐ ๋ฌธ์ ๋ฐ๊ฒฌ โ Mark-Sweep ์ ์์ ์ฑ โ ๋จํธํ ๋ฌธ์ โ Mark-Sweep-Compact์ ์์ถ โ ๋ชจ๋ ๊ฐ์ฒด ๋๊ฐ์ด ๋ค๋ฃจ๋ ๋นํจ์จ โ Generational์ ํจ์จ.
๊ฐ ์๊ณ ๋ฆฌ์ฆ์ ์ด์ ์๊ณ ๋ฆฌ์ฆ์ ํ๊ณ๋ฅผ ํด๊ฒฐ. ์๋ฐ๋ ๊ฐ์ฅ ์งํ๋ ํํ์ธ Generational ์ฑํ, ์ดํ G1, ZGC ๋ฑ์ผ๋ก ๋ ์งํ.
์๊ณ ๋ฆฌ์ฆ ์ฐจ์ด๋ฅผ ๋ชจ๋ฅด๋ฉด ๋ค์ํ ์ํฉ์์ ๋งํ๋๋ค.
๋ฉด์ ์ง๋ฌธ:
"Python ์ฒ๋ผ Reference Counting ์ฐ๋ฉด ์ฆ์ ํ์ ๊ฐ๋ฅํ์ง ์๋์?"
์๊ณ ๋ฆฌ์ฆ ๋ชจ๋ฅด๋ฉด:
์๊ณ ๋ฆฌ์ฆ ์๋ฉด:
์ด์ ํ๊ฒฝ:
Heap ์ฌ์ฉ๋: 70%
๊ทธ๋ฌ๋ 1MB ์ด์ ๊ฐ์ฒด ํ ๋น ์ OOM
์๊ณ ๋ฆฌ์ฆ ๋ชจ๋ฅด๋ฉด:
์๊ณ ๋ฆฌ์ฆ ์๋ฉด:
์ ๊ท ILIC ์์คํ ๋ฐฐํฌ:
์๊ณ ๋ฆฌ์ฆ ๋ชจ๋ฅด๋ฉด:
์๊ณ ๋ฆฌ์ฆ ์๋ฉด:
Python ๊ฐ๋ฐ์๊ฐ ์๋ฐ ์์:
"GC ๊ฐ ์์ฃผ ๋ฉ์ถฐ์. Python ์ ์ ๊ทธ๋ฌ๋๋ฐ?"
์๊ณ ๋ฆฌ์ฆ ๋ชจ๋ฅด๋ฉด:
์๊ณ ๋ฆฌ์ฆ ์๋ฉด:
"GC ์๊ณ ๋ฆฌ์ฆ์ ์งํ๋ฅผ ์ค๋ช ํด์ฃผ์ธ์"
"Mark-Sweep ์ ๋จ์ ์ด ๋ญ๊ฐ์?"
"์ ์๋ฐ๋ Mark-Sweep-Compact ์ Copying ๋ ๋ค ์ฐ๋์?"
์๊ณ ๋ฆฌ์ฆ ๋ชจ๋ฅด๋ฉด:
์๊ณ ๋ฆฌ์ฆ ์๋ฉด:
๊ด์ฐฐ: Heap ์ฌ์ฉ๋ ๊ณ์ ์ฆ๊ฐ
GC ํ์๋ ์ค์ง ์์
์๊ณ ๋ฆฌ์ฆ ๋ชจ๋ฅด๋ฉด:
์๊ณ ๋ฆฌ์ฆ ์๋ฉด:
| ์๋๋ฆฌ์ค | ์๊ณ ๋ฆฌ์ฆ ๋ชจ๋ฅด๋ฉด | ์๊ณ ๋ฆฌ์ฆ ์๋ฉด |
|---|---|---|
| Reference Counting ์ง๋ฌธ | ๋ง๋งํจ | ์ํ ์ฐธ์กฐ ์ค๋ช |
| ๋จํธํ OOM | ์ดํด X | Compact ์๊ณ ๋ฆฌ์ฆ ์ ํ |
| ์ด์ GC ์ ํ | ๊ธฐ๋ณธ ์ฌ์ฉ | ์ํฉ๋ณ ์ ํ |
| ์ธ์ด ๋น๊ต | ํ๋ฉด์ | ๊น์ด ์๋ ๋น๊ต |
| ๋ฉด์ ๊น์ด ์ง๋ฌธ | ํ๋ฝ | ์๋์ด ๋ต๋ณ |
| ๋ฉ๋ชจ๋ฆฌ ๋์ | "GC ๋ฌธ์ " | "์ฐธ์กฐ ๋ฌธ์ " |
โ ์๊ณ ๋ฆฌ์ฆ ์ดํด๋ ์๋์ด์ ์ฐจ๋ณํ ์์ญ.
๋ชจ๋ ๊ฐ์ฒด์ ์ฐธ์กฐ ์นด์ดํธ ๋ณด์ :
๊ฐ์ฒด A:
- ๋ฐ์ดํฐ
- ์ฐธ์กฐ ์นด์ดํธ: 1
์ฐธ์กฐ ์ถ๊ฐ/์ ๊ฑฐ ์:
Object x = a; // a ์ ์นด์ดํธ +1
x = null; // a ์ ์นด์ดํธ -1
์นด์ดํธ 0 โ ์ฆ์ ํ์.
1. ์ฆ๊ฐ์ ํ์
2. STW ์์
3. ๋ถ์ฐ๋ ์์
1. ์ํ ์ฐธ์กฐ ๋ฌธ์ โ ๏ธ (์๊ธฐ ์ ๊ฒ Q1)
class Node {
Node next;
}
Node a = new Node();
Node b = new Node();
a.next = b; // a โ b
b.next = a; // b โ a (์ํ!)
a = null; // a ์ ์ธ๋ถ ์ฐธ์กฐ ๋์
b = null; // b ์ ์ธ๋ถ ์ฐธ์กฐ ๋์
// ๊ทธ๋ฌ๋:
// a ์ ์นด์ดํธ: 1 (b.next ๊ฐ ๊ฐ๋ฆฌํด)
// b ์ ์นด์ดํธ: 1 (a.next ๊ฐ ๊ฐ๋ฆฌํด)
// โ ์นด์ดํธ 0 ์ ๋จ โ ๋ฉ๋ชจ๋ฆฌ ๋์ โ
๊ทธ๋ฆผ:
[Stack] (์ธ๋ถ ์ฐธ์กฐ ์์)
[Heap]
Node A โโ Node B
โ โ
โโโโโโโโ
A ์ ์นด์ดํธ: 1 (B ์ next)
B ์ ์นด์ดํธ: 1 (A ์ next)
โ ๋ ๋ค ํ์ X
2. ์นด์ดํธ ๊ด๋ฆฌ ๋น์ฉ
3. ๋ฉ๋ชจ๋ฆฌ ์ค๋ฒํค๋
| ์ธ์ด | ์ฌ์ฉ |
|---|---|
| Python | Reference Counting + Cycle Detector (๋ณด์กฐ) |
| Objective-C | ARC (Automatic Reference Counting) |
| Swift | ARC |
| C++ | shared_ptr |
| Java | โ ์ฌ์ฉ ์ ํจ |
2๋จ๊ณ:
Mark ๋จ๊ณ:
Sweep ๋จ๊ณ:
[Stack]
ref1, ref2
[Heap]
Object A โโโโ ref1 (Mark)
Object B (X)
Object C โโโโ ref2 (Mark)
Object D โโ A (Mark)
Object E (X)
Step 1: Initial
[Heap]
A B C D E F G H
โ โ โ
GC Root ๋ค
Step 2: Mark
[Heap]
A* B C* D E F* G H
*=๋งํน๋จ (Live)
GC Root ์์ ๋๋ฌ ๊ฐ๋ฅ: A, C, F
Step 3: Sweep
[Heap]
A _ C _ _ F _ _
(B,D,E,G,H ํ์)
1. ์ํ ์ฐธ์กฐ ํด๊ฒฐ
2. ๋จ์ํ ์๊ณ ๋ฆฌ์ฆ
1. STW ํ์
2. ๋จํธํ ๋ฐ์ โ ๏ธ
After Sweep:
[A][_][C][_][_][F][_][_]
โ 8 byte ๋น ๊ณต๊ฐ 5๊ฐ
โ ๊ทธ๋ฌ๋ 16 byte ๊ฐ์ฒด ํ ๋น ๋ถ๊ฐ (์ฐ์ ๊ณต๊ฐ ์์)
3. Mark ์๊ฐ ๋น๋ก
์๋ฐ์ GC ๋ Mark-Sweep ์ ๋ณํ:
3๋จ๊ณ:
Step 1-2: Mark + Sweep (๊ฐ์)
After Sweep:
[A][_][C][_][_][F][_][_]
Step 3: Compact
After Compact:
[A][C][F][_][_][_][_][_]
(์ด์์๋ ๊ฒ ์์ชฝ ๋ชจ์)
(๋น ๊ณต๊ฐ ๋ค๋ก)
1. ๋จํธํ ํด์
2. ๋ฉ๋ชจ๋ฆฌ ํจ์จ
1. Compact ๋น์ฉ
2. STW ๊ธธ์ด์ง
Old Generation ์์ ์ฌ์ฉ:
์ฝํ ์ธ๋ ๊ฐ์ค ํ์ฉ:
Young ์์ญ: Copying GC
Old ์์ญ: Mark-Sweep-Compact
Before Minor GC:
[Eden + From]
A B C D E (B, D ๋ Garbage)
[To]
๋น์ด์์
Copying:
์ด์์๋ A, C, E ๋ฅผ To ๋ก ๋ณต์ฌ
After:
[Eden + From]
๋น์
[To]
A C E
ํจ๊ณผ:
1. ๋งค์ฐ ํจ์จ์
2. ๋จํธํ ํด์
3. ์งง์ STW (๋ณดํต)
1. ๊ตฌ์กฐ ๋ณต์ก
2. ๋ฉ๋ชจ๋ฆฌ ์ค๋ฒํค๋
์๋ฐ ๋ชจ๋ GC ์ ๊ธฐ๋ฐ:
โ ๋ชจ๋ Generational + ์ถ๊ฐ ์ต์ ํ.
| Reference Counting | Mark-Sweep | Mark-Sweep-Compact | Generational | |
|---|---|---|---|---|
| ์ํ ์ฐธ์กฐ | โ ๋์ | โ ํด๊ฒฐ | โ ํด๊ฒฐ | โ ํด๊ฒฐ |
| STW | ์์ | ๊น | ๋งค์ฐ ๊น | ์งง์ (Minor) |
| ๋จํธํ | ์์ | ์์ | ์์ (์์ถ) | ์์ (Young ์๋) |
| ์ฆ์ ํ์ | โ | X | X | X |
| ๊ตฌ์กฐ | ๋จ์ | ๋จ์ | ๋ณดํต | ๋ณต์ก |
| ์๋ฐ ์ฑํ | โ | โณ (๋ณํ) | โณ (Old ์์ญ) | โ |
1. Reference Counting (1950s)
โ ์ํ ์ฐธ์กฐ ๋ฌธ์ ๋ฐ๊ฒฌ
2. Mark-Sweep (1960s)
โ ๋จํธํ ๋ฌธ์ ๋ฐ๊ฒฌ
3. Mark-Sweep-Compact (1970s)
โ ๋ชจ๋ ๊ฐ์ฒด ๊ฐ๊ฒ ๋ค๋ฃจ๋ ๋นํจ์จ
4. Generational (1980s) โญ
โ ์๋ฐ ์ฑํ (1995)
โ ๋ ๋ฐ์
5. G1, ZGC, Shenandoah (2010s+)
โ Region ๊ธฐ๋ฐ, Concurrent
โ ์๊ณ ๋ฆฌ์ฆ ์งํ = GC ์งํ.
# Python ์์ (์๋ฐ ์๋, ์ดํด์ฉ)
a = SomeObject() # a ์ ์นด์ดํธ: 1
b = a # ์นด์ดํธ: 2
a = None # ์นด์ดํธ: 1
b = None # ์นด์ดํธ: 0 โ ์ฆ์ ํ์
JVM ์ด๋ผ๋ฉด (๊ฐ์):
// ์์ฌ ์ฝ๋ โ ์๋ฐ๋ ์ด๋ ๊ฒ ์ ํจ
class Object {
int referenceCount;
void onReferenceAdded() { referenceCount++; }
void onReferenceRemoved() {
referenceCount--;
if (referenceCount == 0) {
free(this); // ์ฆ์ ํด์
}
}
}
๋ชจ๋ ์ฐธ์กฐ ๋ณ๊ฒฝ ์ ์นด์ดํธ ๊ฐฑ์ โ ๋น์ฉ ๋์.
class Person {
Person friend; // ์น๊ตฌ ์ฐธ์กฐ
}
// ์๋๋ฆฌ์ค
Person alice = new Person(); // alice: cnt=1 (์ธ๋ถ ๋ณ์)
Person bob = new Person(); // bob: cnt=1
alice.friend = bob; // bob: cnt=2
bob.friend = alice; // alice: cnt=2
alice = null; // alice ๊ฐ์ฒด: cnt=1 (bob.friend ๊ฐ ๊ฐ๋ฆฌํด)
bob = null; // bob ๊ฐ์ฒด: cnt=1 (alice.friend ๊ฐ ๊ฐ๋ฆฌํด)
// ์ธ๋ถ ์ฐธ์กฐ ๋ชจ๋ ๋๊ฒผ๋๋ฐ
// ์๋ก 1์ฉ ์นด์ดํธ โ ์์ํ ํ์ X
์๊ฐํ:
[Stack] (๋น์ด์์ โ ์ธ๋ถ ์ฐธ์กฐ X)
[Heap]
alice ๊ฐ์ฒด (cnt=1) โโโ bob ๊ฐ์ฒด (cnt=1)
โ โ
โโโโโโโโโโโโโโโโโโโโโโ
(cycle)
โ ๋์.
Mark-Sweep ์ด๋ผ๋ฉด ํด๊ฒฐ:
GC Root: ์ธ๋ถ ์ฐธ์กฐ ์์
โ Reachability: alice, bob ๋ ๋ค ๋๋ฌ ๋ถ๊ฐ
โ Sweep ์ ํ์
DFS (Depth-First Search) ์ฌ์ฉ:
1. GC Root ๋ค์ work-list ์ ์ถ๊ฐ
2. while work-list ๋น์ด์์ง ์์:
a. ๊ฐ์ฒด ํ๋ ๊บผ๋
b. ๋งํน
c. ๊ทธ ๊ฐ์ฒด์ ๋ชจ๋ ์ฐธ์กฐ๋ฅผ work-list ์ ์ถ๊ฐ
3. ๋๋๋ฉด ๋งํน ์ ๋ ๊ฒ์ด Garbage
์๊ฐ ๋ณต์ก๋:
for each ๊ฐ์ฒด in Heap:
if ๋งํน ์ ๋จ:
free(๊ฐ์ฒด)
else:
clear_mark(๊ฐ์ฒด) // ๋ค์ GC ์ํด
Free List:
๊ฐ์ฒด ์ด๋ + ์ฐธ์กฐ ์ ๋ฐ์ดํธ:
Step 1: ์ ์์น ๊ณ์ฐ
A: 0x1000 โ 0x1000 (๊ทธ๋๋ก)
C: 0x2000 โ 0x1100 (์์ผ๋ก ์ด๋)
F: 0x3000 โ 0x1200 (์์ผ๋ก ์ด๋)
Step 2: ๊ฐ์ฒด ๋ณต์ฌ
C ์ ๋ฐ์ดํฐ โ 0x1100
F ์ ๋ฐ์ดํฐ โ 0x1200
Step 3: ๋ชจ๋ ์ฐธ์กฐ ์
๋ฐ์ดํธ
A ๊ฐ C ๋ฅผ ์ฐธ์กฐ โ 0x2000 โ 0x1100
์ธ๋ถ์์ F ์ฐธ์กฐ โ 0x3000 โ 0x1200
๋น์ฉ:
Young ์์ญ์์ ์ฌ์ฉ:
Eden + From: [A][B][C][D][E]
โ Live: A, C, E
To: ๋น์ด์์
โ Copying
To: [A][C][E]
Eden + From: ํต์งธ๋ก ๋น์
์ ๋น ๋ฅธ๊ฐ:
1. ์ด์์๋ ๊ฐ์ฒด๋ง ๋ณต์ฌ (๋ณดํต ์ ์)
2. ๋น ๊ณต๊ฐ ํต์งธ๋ก ๋น์ (free ํธ์ถ ์์)
3. ์๋ ์์ถ (๋ณ๋ ๋จ๊ณ X)
์๊ฐ: O(Live ๊ฐ์ฒด ์)
์ ๊ฐ์ฒด ์์ฑ:
โ Eden ํ ๋น
Eden ๊ฐ๋:
โ Minor GC (Copying)
โ Eden + From โ To
โ ์ด์๋จ์ ๊ฐ์ฒด age +1
Survivor ๊ฐ๋ ๋๋ age = 15:
โ Promotion (Old ๋ก ์ด๋)
Old ๊ฐ๋:
โ Major GC (Mark-Sweep-Compact)
โ ๋๋ G1 ์ Mixed GC
Old + Metaspace ๊ฐ๋:
โ Full GC (์ ์ฒด)
๋ฌธ์ : Old โ Young ์ฐธ์กฐ
@Service
public class FareCache { // Old ์ ์ด์์์
private List<Fare> recent = new ArrayList<>(); // Young ์ ์์ ์ ์์
}
Minor GC ์ Eden + From ๋ง ๋ณด๋ฉด, Old ์ cache ๊ฐ ๊ฐ๋ฆฌํค๋ Young ๊ฐ์ฒด ๋ฅผ Live ๋ก ์ธ์ ๋ชป ํจ.
ํด๊ฒฐ โ Card Table โญ :
[Old]
Region 0: [Card 0][Card 1][Card 2][Card 3]
โ
dirty (Young ์ฐธ์กฐ ์์)
Minor GC:
1. GC Root ์ค์บ
2. dirty ์นด๋๋ง ์ถ๊ฐ ์ค์บ
3. ๋งํน
Write Barrier:
// ์ฌ์ฉ์ ์ฝ๋
oldObject.youngRef = youngObject;
// JVM ๋ด๋ถ (์ค์ ๋ฐ์ดํธ์ฝ๋)
oldObject.youngRef = youngObject;
markCardAsDirty(oldObject); // โ Write Barrier
โ Generational GC ์ ํต์ฌ ๋ฉ์ปค๋์ฆ.
class Person {
String name;
Person friend;
Person(String name) {
this.name = name;
}
}
public class CycleDemo {
public static void main(String[] args) {
Person alice = new Person("Alice");
Person bob = new Person("Bob");
alice.friend = bob;
bob.friend = alice;
// ์ธ๋ถ ์ฐธ์กฐ ๋์
alice = null;
bob = null;
// GC ๋ฐ์ ์ โ Mark-Sweep ์ด๋ฏ๋ก ๋ ๋ค ํ์ โ
// (Reference Counting ์ด์๋ค๋ฉด ๋์)
System.gc();
}
}
โ ์๋ฐ = Mark-Sweep ๊ธฐ๋ฐ โ ์ํ ์ฐธ์กฐ ์์ .
// โ ์๋ฐ์์ ์ค์ ๋ฉ๋ชจ๋ฆฌ ๋์ ํจํด
public class CacheDemo {
private static final List<Customer> cache = new ArrayList<>();
public static void addCustomer(Customer c) {
cache.add(c);
// cache ๋ static โ GC Root
// cache ๊ฐ c ๋ฅผ ์ฐธ์กฐ โ c ์์ํ Live
// โ ๋์
}
}
โ ์๋ฐ๋ ์ฐธ์กฐ๊ฐ ์ด์์์ผ๋ฉด GC ๋ชป ํจ. Mark-Sweep ์ด๋ผ๋.
public class GCVisualizer {
// ์๋๋ฆฌ์ค: 100๊ฐ ๊ฐ์ฒด ์์ฑ, ์ ๋ฐ์ ์ด๋ฆฌ๊ธฐ
public static void main(String[] args) {
List<byte[]> survivors = new ArrayList<>();
for (int i = 0; i < 100; i++) {
byte[] data = new byte[1024 * 100]; // 100KB
if (i % 2 == 0) {
survivors.add(data); // ์ ๋ฐ๋ง ์ด๋ฆผ
}
// ๋๋จธ์ง๋ ๋ฉ์๋ ์ข
๋ฃ ์ Garbage
}
System.out.println("์ค์ ์ด์์๋ ๊ฐ์ฒด: 50");
System.out.println("์ด ์์ฑ ๊ฐ์ฒด: 100");
// โ 50 ํ์ ํ์
System.gc();
System.out.println("GC ํ โ 50 ํ์๋จ");
}
}
์๊ณ ๋ฆฌ์ฆ๋ณ ๋์:
// ILIC ์ด์ ํ๊ฒฝ โ JVM ์ต์
// -XX:+UseSerialGC // Serial (๋จ์ผ ์ค๋ ๋)
// -XX:+UseParallelGC // Parallel (๋ฉํฐ ์ค๋ ๋)
// -XX:+UseG1GC // G1 (Region ๊ธฐ๋ฐ) โ Java 9+ ๊ธฐ๋ณธ
// -XX:+UseZGC // ZGC (์ ์ง์ฐ)
// ๊ถ์ฅ:
java -XX:+UseG1GC \
-Xms2g -Xmx2g \
-XX:MaxGCPauseMillis=200 \
-Xlog:gc*:file=gc.log \
-jar ilic.jar
์ ํ ๊ธฐ์ค:
java -XX:+PrintCommandLineFlags -version
์ถ๋ ฅ ์์:
-XX:InitialHeapSize=...
-XX:+UseG1GC โ ์ฌ์ฉ ์ค์ธ GC
-XX:+UseCompressedClassPointers
...
๋๋:
java -Xlog:gc*:stdout YourApp
GC ๋ก๊ทธ์์ ์๊ณ ๋ฆฌ์ฆ ์ด๋ฆ ํ์ธ ๊ฐ๋ฅ.
public class FragmentationDemo {
public static void main(String[] args) {
List<byte[]> arrays = new ArrayList<>();
// 100๊ฐ ์์ ๋ฐฐ์ด ํ ๋น
for (int i = 0; i < 100; i++) {
arrays.add(new byte[1024 * 100]); // 100KB
}
// ์ง์ ์ธ๋ฑ์ค๋ง ์ด๋ฆผ (ํ์๋ Garbage ๋์)
for (int i = 1; i < 100; i += 2) {
arrays.set(i, null);
}
System.gc(); // GC ๋ฐ์
// Mark-Sweep ๋ง ํ๋ค๋ฉด:
// ์ด์์๋ ๊ฒ: [A][_][C][_][E][_][G][_]...
// โ ๋จํธํ โ ๏ธ
// Mark-Sweep-Compact ํ:
// [A][C][E][G][_][_][_][_][_]...
// โ ์์ถ โ
// ํฐ ๊ฐ์ฒด ํ ๋น ์๋
try {
byte[] huge = new byte[1024 * 1024 * 50]; // 50MB
// Mark-Sweep ๋ง์ด๋ผ๋ฉด OOM ๊ฐ๋ฅ
// Compact ํ๋ผ๋ฉด OK
} catch (OutOfMemoryError e) {
System.out.println("๋จํธํ๋ก OOM!");
}
}
}
โ ์๋ฐ๋ Compact ๊ฐ ์์ด ์์ . C/C++ ๋ฑ์์๋ ๋จํธํ ์ํ.
# Parallel GC (Java 8 ๊ธฐ๋ณธ)
java -XX:+UseParallelGC -Xmx2g -jar ilic.jar
# ๊ฒฐ๊ณผ: Throughput ๋์, Full GC ์ STW 1์ด
# G1 GC (Java 9+ ๊ธฐ๋ณธ)
java -XX:+UseG1GC -Xmx2g -jar ilic.jar
# ๊ฒฐ๊ณผ: Throughput ์ฝ๊ฐ ๋ฎ์, STW ~200ms
# ZGC (Java 11+)
java -XX:+UseZGC -Xmx2g -jar ilic.jar
# ๊ฒฐ๊ณผ: Throughput ์ฝ๊ฐ ๋ ๋ฎ์, STW ~10ms
์ ํ ๊ธฐ์ค:
Q: "์๋ฐ GC ์๊ณ ๋ฆฌ์ฆ?"
A: "Reference Counting ๊ฐ์ ๊ฑฐ?" โ
์ ๋ต: ์๋ฐ๋ Generational + Mark-Sweep-Compact ์ฌ์ฉ. Reference Counting ์ฌ์ฉ ์ ํจ.
"์ํ ์ฐธ์กฐ ๋ง๋ค๋ฉด ๋ฉ๋ชจ๋ฆฌ ๋์๋ค!"
์ง์ค: ์๋ฐ๋ Mark-Sweep ๊ธฐ๋ฐ์ด๋ผ ์ํ ์ฐธ์กฐ ์์ .
// ์๋ฐ์์๋ OK
a.friend = b;
b.friend = a;
a = null;
b = null;
// โ GC ์ ๋ ๋ค ํ์
์ํ ์ฐธ์กฐ๊ฐ ๋์์ธ ๊ฒฝ์ฐ๋ ์ธ๋ถ์์๋ ์ฐธ์กฐ ํ ๋:
static List<Person> all = new ArrayList<>();
all.add(alice);
all.add(bob);
// โ all ์ด ์ด์์์ด ๋ ๋ค ๋์
"์๋ฐ๋ Mark-Sweep ์ฌ์ฉํฉ๋๋ค"
์ ๋ต: Generational + Mark-Sweep-Compact (Old) + Copying (Young).
๊ฐ ์์ญ๋ง๋ค ๋ค๋ฅธ ์๊ณ ๋ฆฌ์ฆ.
"GC ๋์ ํญ์ 1์ด์ฉ ๋ฉ์ถฐ์"
์ ๋ต:
GC ์๊ณ ๋ฆฌ์ฆ + Heap ํฌ๊ธฐ์ ๋ฐ๋ผ ๋ค๋ฆ. ZGC ๋ฉด ms ๋จ์.
Q: "Mark-Sweep ๋จํธํ๋?"
A: "Compact ์์ด์ OK ์๋๊ฐ์?" โ
์ ๋ต: ์์ Mark-Sweep ์ Compact ์์. ๋จํธํ ๋ฐ์.
์๋ฐ์ Old GC ๋ Mark-Sweep-Compact (์์ถ ์ถ๊ฐ).
java -jar myapp.jar # ๊ธฐ๋ณธ GC ์ฌ์ฉ
๋ฌธ์ :
์ํฉ๋ณ ๊ถ์ฅ:
public void process() {
// ์ฒ๋ฆฌ
System.gc(); // โ ๊ถ์ฅ X
}
๋ฌธ์ :
์์น: GC ๋ JVM ์ด ์์์.
[Unit 5.1: GC ๊ธฐ๋ณธ + ์ฝํ ์ธ๋ ๊ฐ์ค] โ
โ
[Unit 5.2: Heap ์ ์ธ๋ ๊ตฌ์กฐ] โ
โ
[Unit 5.3: GC ์๊ณ ๋ฆฌ์ฆ 4๊ฐ์ง] โ ์ง๊ธ ์ฌ๊ธฐ โ
โ
[Unit 5.4: GC ์ข
๋ฅ์ ์ ํ ๊ธฐ์ค] (๋ง์ง๋ง)
| ์๊ธฐ | ์๊ณ ๋ฆฌ์ฆ | ์ฃผ์ ๊ฐ์ |
|---|---|---|
| 1950s | Reference Counting | ์ฆ์ ํ์ |
| 1960s | Mark-Sweep | ์ํ ์ฐธ์กฐ ํด๊ฒฐ |
| 1970s | Mark-Sweep-Compact | ๋จํธํ ํด๊ฒฐ |
| 1980s | Generational | ํจ์จ โ |
| 1990s | Concurrent (CMS) | STW ์งง์ |
| 2010s | G1 (Region) | ํฐ Heap |
| 2010s | ZGC | ๋งค์ฐ ์งง์ STW |
| ์ธ์ด | GC ์๊ณ ๋ฆฌ์ฆ |
|---|---|
| Java | Generational + Mark-Sweep-Compact + Copying |
| C#/.NET | Generational + Mark-Sweep-Compact (๋น์ท) |
| Go | Concurrent Mark-Sweep (์ ์ง์ฐ ์ฐ์ ) |
| Python | Reference Counting + Cycle Detector |
| JavaScript (V8) | Generational + Mark-Sweep |
| Ruby | Mark-Sweep-Compact + Generational |
| Rust | GC ์์ (์์ ๊ถ) |
| ์ง๋ฌธ | ์ด Unit์์์ ๋ต |
|---|---|
| "GC ์๊ณ ๋ฆฌ์ฆ?" | RC, Mark-Sweep, MSC, Generational |
| "์ ์๋ฐ๋ RC ์ ์?" | ์ํ ์ฐธ์กฐ + ์นด์ดํธ ๋น์ฉ |
| "Mark-Sweep ๋จ์ ?" | ๋จํธํ |
| "์๋ฐ GC ์ ํน์ง?" | Generational + ์์ญ๋ณ ๋ค๋ฅธ ์๊ณ ๋ฆฌ์ฆ |
| "Copying GC?" | Young ์์ญ์์ ์ฌ์ฉ |
1๏ธโฃ GC ์๊ณ ๋ฆฌ์ฆ์ 4๊ฐ์ง โ Reference Counting, Mark-Sweep, Mark-Sweep-Compact, Generational.
Reference Counting ์ ์ฐธ์กฐ ์นด์ดํธ๋ก ์ฆ์ ํ์, ์ํ ์ฐธ์กฐ ์ ๋์. Mark-Sweep ์ GC Root ์ถ์ ์ผ๋ก ๋งํน ํ ํ์, ๋จํธํ ๋ฐ์. Mark-Sweep-Compact ์ ์์ถ ์ถ๊ฐ๋ก ๋จํธํ ํด์. Generational ์ ์ฝํ ์ธ๋ ๊ฐ์ค๋ก ์์ญ๋ณ ๋ค๋ฅธ ์๊ณ ๋ฆฌ์ฆ ์ ์ฉ.
2๏ธโฃ ์๋ฐ๋ Generational + ์์ญ๋ณ ๋ค๋ฅธ ์๊ณ ๋ฆฌ์ฆ์ ์ฌ์ฉํ๋ค.
Young ์์ญ (Eden + Survivor) ์ Copying GC โ Eden + From ์ ์ด์์๋ ๊ฐ์ฒด๋ฅผ To ๋ก ๋ณต์ฌ, ์๋ ์์ถ. Old ์์ญ์ Mark-Sweep-Compact โ ๋งํน + ํ์ + ์์ถ. Reference Counting ์ ์ฌ์ฉ X (์ํ ์ฐธ์กฐ + ์นด์ดํธ ๋น์ฉ ๋๋ฌธ). Card Table + Write Barrier ๋ก Old โ Young ์ฐธ์กฐ ์ถ์ .
3๏ธโฃ ์๊ณ ๋ฆฌ์ฆ ์ ํ = ํจ์จ / ๋จํธํ / STW ์ trade-off.
Reference Counting: ์ฆ์ ํ์, ๋ฉ์ถค X / ์ํ ์ฐธ์กฐ ๋์. Mark-Sweep: ๋จ์, ์์ / ๋จํธํ. Compact: ๋จํธํ ํด์ / STW ๊ธธ์ด์ง. Generational: ์ฝํ ์ธ๋ ๊ฐ์ค๋ก ๊ท ํ / ๊ตฌ์กฐ ๋ณต์ก. Java ์ ๋ชจ๋ GC (Serial, Parallel, CMS, G1, ZGC) ๊ฐ Generational + ์ถ๊ฐ ์ต์ ํ. ์ด์ ์ G1 (๊ท ํ) ๋๋ ZGC (์ ์ง์ฐ) ๊ถ์ฅ.
Q1: ์ํ ์ฐธ์กฐ๊ฐ Reference Counting ์์ ์ ๋ฌธ์ ์ธ์ง ๊ทธ๋ฆผ์ผ๋ก ๊ทธ๋ ค๋ณด๋ผ.
๋ต: ์ธ๋ถ ์ฐธ์กฐ๊ฐ ๋ชจ๋ ๋๊ฒผ๋๋ฐ, ๊ฐ์ฒด๋ผ๋ฆฌ ์ํธ ์ฐธ์กฐ ํ๋ฉด ์นด์ดํธ๊ฐ 0 ์ ๋ผ์ ๋์.
์์ธ ์๊ฐํ:
[Stack]
alice (๋ณ์)
bob (๋ณ์)
[Heap]
Person "Alice" cnt=1 (alice ๊ฐ ๊ฐ๋ฆฌํด)
Person "Bob" cnt=1 (bob ์ด ๊ฐ๋ฆฌํด)
alice.friend = bob; // bob: cnt=2 (alice.friend ๊ฐ ๊ฐ๋ฆฌํด)
bob.friend = alice; // alice: cnt=2 (bob.friend ๊ฐ ๊ฐ๋ฆฌํด)
[Stack]
alice โโโโโ
bob โโโโโโโผโโ
โ โ
[Heap] โผ โผ
Person "Alice" cnt=2 โโโ Person "Bob" cnt=2
โ โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโ
alice = null; // alice ๊ฐ์ฒด: cnt=2-1=1
bob = null; // bob ๊ฐ์ฒด: cnt=2-1=1
[Stack] (๋น์ด์์)
[Heap]
Person "Alice" cnt=1 โโโ Person "Bob" cnt=1
โ โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโ
๋ ๊ฐ์ฒด ๋ชจ๋ cnt=1 (์๋ก ๊ฐ๋ฆฌํด)
โ ์์ํ cnt=0 ์ ๋จ
โ ๋ฉ๋ชจ๋ฆฌ ๋์ โ
ํต์ฌ ๋ฌธ์ :
ํด๊ฒฐ์ฑ ๋ค:
์ฃผ๊ธฐ์ ์ผ๋ก:
- ์นด์ดํธ 0 ์ ๋์ง๋ง ๋๋ฌ ๋ถ๊ฐ๋ฅํ ๊ฐ์ฒด ์๋ณ
- ๊ทธ๊ฒ๋ค ํ์
GC Root ์์ ์์
โ alice, bob ๊ฐ์ฒด ๋๋ฌ ๋ถ๊ฐ
โ Mark ์ ๋จ
โ Sweep ์ ํ์
class Person {
WeakReference<Person> friend; // ์ฝํ ์ฐธ์กฐ
// โ ์นด์ดํธ ์ฆ๊ฐ X
// โ ์ํ ์ฐธ์กฐ ๋ฐ์ X
}
โ ์๋ฐ๋ Mark-Sweep ์ผ๋ก ์ฐ์ํ๊ฒ ํด๊ฒฐ.
Q2: Mark-and-Sweep ์์ OOM ์ด ๋ฐ์ํ ์ ์๋ ์ด์ ๋?
ํ ์ค ๋ต: ๋จํธํ (Fragmentation) ๋๋ฌธ์ ํฐ ์ฐ์ ๊ณต๊ฐ ๋ถ์กฑ.
์์ธ ์ค๋ช :
Mark-Sweep ๋ง ์ฌ์ฉ ์ Compact ๋จ๊ณ ์์:
[Heap] (1GB)
[๊ฐ์ฒดA 100MB][๊ฐ์ฒดB 100MB][๊ฐ์ฒดC 100MB][๊ฐ์ฒดD 100MB][๊ฐ์ฒดE 100MB]
... 10๊ฐ 100MB ๊ฐ์ฒด๋ก ๊ฐ๋
Mark:
A (Live), B (Garbage), C (Live), D (Garbage), E (Live), ...
Sweep:
[A 100MB][_ 100MB][C 100MB][_ 100MB][E 100MB][_ 100MB]...
โ ๋น ๊ณต๊ฐ๋ค ํฉ์ด์ง
byte[] big = new byte[300 * 1024 * 1024]; // 300MB
๋ฌธ์ :
์๊ฐํ:
๋น ๊ณต๊ฐ๋ค:
100MB(B) + 100MB(D) + 100MB(F) + 100MB(H) + 100MB(J) = 500MB
๊ทธ๋ฌ๋ ์์น:
[A][__][C][__][E][__][G][__][I][__]
โ ์ฐ์ 100MB ๋ง
โ "๋ฉ๋ชจ๋ฆฌ ๋ถ์กฑ" ์ด ์๋ "์ฐ์๋ ๊ณต๊ฐ ๋ถ์กฑ".
์ฃผ์ฐจ์ฅ (10๋ ์ฃผ์ฐจ ๊ฐ๋ฅ):
[์ฐจ1][_][์ฐจ3][_][์ฐจ5][_][์ฐจ7][_][์ฐจ9][_]
๋น ์๋ฆฌ: 5๊ฐ (์ ๋ฐ ๋น์ด์์)
๊ทธ๋ฌ๋ ํธ๋ญ (3๋ ์๋ฆฌ ํ์):
โ ์ฐ์ 3๋ ์๋ฆฌ ์์
โ ์ฃผ์ฐจ ๋ถ๊ฐ โ ๏ธ
Compact ํ:
[์ฐจ1][์ฐจ3][์ฐจ5][์ฐจ7][์ฐจ9][_][_][_][_][_]
โ ์ฐ์๋ ๋น ๊ณต๊ฐ
์ด์ ํธ๋ญ ์ฃผ์ฐจ ๊ฐ๋ฅ โ
์๋ฐ์ Old GC = Mark-Sweep-Compact:
โ ์๋ฐ๊ฐ Mark-Sweep-Compact ์ฑํํ ์ด์ .
G1 GC ๋ Region ๊ธฐ๋ฐ:
G1 ์ Humongous Object: