F-lab Java 1์ฃผ์ฐจ / Phase 5 / Unit 5.2 ๋ณธ๊ฒฉ ํ์ต ์๋ฃ
9-์น์ ๋ง์คํฐ ํ๋กฌํํธ ํ์์ผ๋ก ๊น์ด ํํค์น๋ค.์ ์ ์ง์: Unit 5.1 (GC์ ๊ธฐ๋ณธ ๊ฐ๋ ๊ณผ ์ฝํ ์ธ๋ ๊ฐ์ค)
๋ค์ Unit: 5.3 โ GC ์๊ณ ๋ฆฌ์ฆ 4๊ฐ์ง์ด Unit์ ์๋ฏธ: ์ฝํ ์ธ๋ ๊ฐ์ค์ ๊ตฌ์ฒด์ ๊ตฌํ.
"Heap์ด ์ด๋ป๊ฒ ๋๋์ด ์๊ณ , ๊ฐ์ฒด๊ฐ ์ด๋ค ์ผ์์ ์ฌ๋๊ฐ" ์ ์ ํํ ์ดํด.
Minor GC vs Major GC vs Full GC ์ ์ฐจ์ด โ ๋ฉด์ ๋จ๊ณจ.
ํฐ ๋ณ์์ ์์ํด๋ณด์ธ์. ํ์๊ฐ ๋ค์ด์ค๋ฉด ์ด๋ป๊ฒ ๋ถ๋ฅํ ๊น์?
1์ธต โ ์๊ธ์ค (Eden):
2์ธต โ ์ผ๋ฐ ๋ณ๋ (Survivor):
3์ธต โ ์ฅ๊ธฐ ์ ์ ๋ณ๋ (Old):
๋ณ์์ ์ด์ ์๋ฆฌ:
โ ์ด๊ฒ ์๋ฐ Heap์ ์ธ๋ ๊ตฌ์กฐ.
์ํฉ: ์ํํธ๊ฐ 3๊ฐ ์๋ค๊ณ ์์.
์ํํธ A (Eden):
์ํํธ B & C (Survivor 0, Survivor 1):
์ํํธ D (Old):
์ Survivor๊ฐ 2๊ฐ?:
โ ์ด๊ฒ Eden + Survivor 0/1 ์ ์ด์ ์๋ฆฌ.
"์๋ฐ Heap์ ๊ฐ์ฒด์ ์๋ช ์ ๋ฐ๋ผ ์์ญ์ ๋๋๊ณ , ๋ค๋ฅธ GC ์ ๋ต์ ์ ์ฉํ๋ค."
3๊ฐ์ง ํต์ฌ ์์ญ:
๋น์ ์ ๋ฆฌ:
| ๋น์ ์์ | Heap ์ ์ฉ |
|---|---|
| ์๊ธ์ค | Eden |
| ์ผ๋ฐ ๋ณ๋ (2๊ฐ) | Survivor 0, Survivor 1 |
| ์ฅ๊ธฐ ์ ์ ๋ณ๋ | Old Generation |
| ์๊ธ์ค ์ฒญ์ | Minor GC |
| ์ฅ๊ธฐ ๋ณ๋ ์ฒญ์ | Major GC |
| ์ ์ฒด ์ฒญ์ | Full GC |
Java ์ด๊ธฐ (1.0~1.4) ์ GC ๋ Heap ์ ์ฒด๋ฅผ ํ ๋ฒ์ ์ฒญ์ํ์ต๋๋ค.
๋ฌธ์ :
์์ธ ๋ถ์:
์ฝํ ์ธ๋ ๊ฐ์ค (Unit 5.1) ํ์ฉ:
"๋๋ถ๋ถ ๊ฐ์ฒด๋ ๋จ๋ช , ์ด์๋จ์ ๊ฒ์ ์ฅ์"
์์ด๋์ด:
์ค์ธก ํจ๊ณผ:
์ฒ์์๋ Young Generation ์ด ๋จ์ํ์ต๋๋ค:
๋ฌธ์ :
ํด๊ฒฐ โ Survivor ์์ญ โญ :
Eden โโโ Survivor (๋ช ํ) โโโ Old
(ํํฐ๋ง)
ํจ๊ณผ:
์ Survivor ๊ฐ 2๊ฐ?
๋ต: Copying GC ๋ฅผ ํ์ฉํ๊ธฐ ์ํด.
Copying GC:
Survivor 0 (From) โ Survivor 1 (To) ์ด์:
Round 1:
[Eden + Survivor 0] โ Survivor 1
(์ด์๋จ์ ๊ฐ์ฒด ๋ณต์ฌ)
Eden ๋น์, Survivor 0 ๋น์
Round 2:
[Eden + Survivor 1] โ Survivor 0
(์ญ๋ฐฉํฅ)
Eden ๋น์, Survivor 1 ๋น์
... ๋ฐ๋ณต ...
ํต์ฌ:
โ ์ด๊ฒ Eden + Survivor 0/1 ์ ์ ํํ ์ด์ ์๋ฆฌ.
๋ฌธ์ : Old โ Young ์ฐธ์กฐ๊ฐ ์์ ์ ์์.
public class OldObject {
private YoungObject young; // Old โ Young ์ฐธ์กฐ
}
Minor GC ์ Young ๋ง ๋ณด๋ฉด ์ด ์ฐธ์กฐ๋ฅผ ๋์น ์ ์์.
ํด๊ฒฐ โ Card Table (Unit 5.1 ๋ฏธ๋ฆฌ๋ณด๊ธฐ):
โ ์ฝํ ์ธ๋ ๊ฐ์ค ๋๋ถ์ Old โ Young ์ฐธ์กฐ๋ ์ ์ โ ํจ์จ์ .
"Heap์ ์ธ๋ ๊ตฌ์กฐ๋ ์ฝํ ์ธ๋ ๊ฐ์ค์ ์ ํํ ๋ฐ์ํ ์ ๊ตํ ์์คํ ์ด๋ค."
Eden + Survivor 0/1 + Old ๋ก ๋ถ๋ฆฌ, Copying GC ๋ก ์๋ ์์ถ, Card Table ๋ก ์ธ๋ ๊ฐ ์ฐธ์กฐ ์ถ์ , Promotion ์ผ๋ก ์ง์ง ์ฅ์ ๊ฐ์ฒด ๋ถ๋ฆฌ. ๋ชจ๋ ๊ฒฐ์ ์ด "๊ฐ์ค์ ์ด๋ป๊ฒ ํจ์จ์ ์ผ๋ก ํ์ฉํ ๊น" ์ ๋ต.
์ด ๊ตฌ์กฐ๋ฅผ ์ ํํ ์ดํดํ๋ฉด GC ์๊ณ ๋ฆฌ์ฆ (Unit 5.3), GC ์ข ๋ฅ (Unit 5.4), ์ด์ ํ๊ฒฝ GC ํ๋๊น์ง ์์ฐ์ค๋ฝ๊ฒ ํก์.
์ธ๋ ๊ตฌ์กฐ๋ฅผ ๋ชจ๋ฅด๋ฉด GC ๊ด๋ จ ๋ฌธ์ ๋ถ์์ด ์ด๋ ต์ต๋๋ค.
์ด์ ํ๊ฒฝ GC ๋ก๊ทธ:
GC(0) Pause Young 25M->2M(64M) 5ms
GC(1) Pause Young 27M->3M(64M) 6ms
GC(2) Pause Young 25M->2M(64M) 5ms
... 1์ด๋ง๋ค ๋ฐ์ ...
์ธ๋ ๊ตฌ์กฐ ๋ชจ๋ฅด๋ฉด:
์ธ๋ ๊ตฌ์กฐ ์๋ฉด:
-Xmn4g (Young ์์ญ 4GB)-XX:NewRatio ์กฐ์ GC ๋ก๊ทธ:
GC(0) Pause Young 25M->20M(64M) 5ms โ Old๋ก ๋ง์ด Promotion
GC(1) Pause Young 30M->25M(64M) 6ms
...
GC(50) Pause Full 60M->50M(64M) 200ms โ Full GC ๋ฐ์
์ธ๋ ๊ตฌ์กฐ ๋ชจ๋ฅด๋ฉด:
์ธ๋ ๊ตฌ์กฐ ์๋ฉด:
GC ๋ก๊ทธ:
[GC pause (G1 Evacuation Pause) (young) (to-space exhausted)]
์๋ฏธ: Survivor ๋๋ Old ๊ฐ ๊ฐ๋ ์ฐจ์ Promotion ์คํจ.
์ธ๋ ๊ตฌ์กฐ ๋ชจ๋ฅด๋ฉด:
์ธ๋ ๊ตฌ์กฐ ์๋ฉด:
byte[] hugeArray = new byte[100 * 1024 * 1024]; // 100MB
์ธ๋ ๊ตฌ์กฐ ๋ชจ๋ฅด๋ฉด:
์ธ๋ ๊ตฌ์กฐ ์๋ฉด:
"๊ฐ์ฒด์ ์ผ์์ ์ค๋ช ํด์ฃผ์ธ์"
"Survivor ๊ฐ 2๊ฐ์ธ ์ด์ ?"
"Promotion ์ด ๋ญ๊ฐ์?"
๋ต ๋ชปํจ:
์ ๋ตํจ:
ILIC ์ด์ ํ๊ฒฝ:
- Heap: 4GB
- ํ๊ท ์๋ต: 50ms
- ๊ฐ๋ ์๋ต: 500ms ~ 1s
๋ถ์:
GC ๋ก๊ทธ โ Major GC ๊ฐ ๊ฐ๋ ๋ฐ์ (200~800ms)
์ธ๋ ๊ตฌ์กฐ ๋ชจ๋ฅด๋ฉด:
์ธ๋ ๊ตฌ์กฐ ์๋ฉด:
| ์๋๋ฆฌ์ค | ์ธ๋ ๋ชจ๋ฅด๋ฉด | ์ธ๋ ์๋ฉด |
|---|---|---|
| Minor GC ๋น๋ | ๋ง๋งํจ | Eden ํฌ๊ธฐ ์กฐ์ |
| Old ๋นจ๋ฆฌ ์ฐธ | ์์ธ ๋ชจ๋ฆ | Survivor / Threshold ๋ถ์ |
| Promotion Failure | ๋ฉ์์ง ๋ชป ์ฝ์ | ์ ํํ ์ง๋จ |
| ๊ฑฐ๋ ๊ฐ์ฒด | ์ฒ๋ฆฌ ๋ชจ๋ฆ | Humongous ์ธ์ง |
| ๋ฉด์ | ํ๋ฝ | ์๋์ด ์ธ์ |
| ์ด์ ๋ถ์ | ํ๋ฉด์ | ๊ทผ๋ณธ ํด๊ฒฐ |
โ ์ธ๋ ๊ตฌ์กฐ๋ ์๋ฐ ์ด์์ ํ์.
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ Heap โ
โ โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โ โ Young Generation (์์) โ โ
โ โ โ โ
โ โ โโโโโโโโโโโโโโ โ โ
โ โ โ Eden โ (๋ณดํต 8/10) โ โ
โ โ โโโโโโโโโโโโโโ โ โ
โ โ โโโโโโ โโโโโโ โ โ
โ โ โ S0 โ โ S1 โ (๊ฐ 1/10) โ โ
โ โ โโโโโโ โโโโโโ โ โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โ โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โ โ Old Generation (ํผ) โ โ
โ โ (์ฅ์ ๊ฐ์ฒด) โ โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
๊ธฐ๋ณธ ๋น์จ (HotSpot JVM):
JVM ์ต์ ์ผ๋ก ์กฐ์ :
-Xms2g -Xmx2g # ์ ์ฒด Heap 2GB
-Xmn800m # Young 800MB (๋๋ -XX:NewSize)
-XX:NewRatio=2 # Young : Old = 1 : 2 (๊ธฐ๋ณธ)
-XX:SurvivorRatio=8 # Eden : S = 8 : 1 (๊ธฐ๋ณธ)
๊ฐ์ฒด๊ฐ ๋ง๋ค์ด์ง๊ณ ์ฌ๋ผ์ง๋ ์ ์ฒด ํ๋ฆ:
Customer alice = new Customer("Alice");
// โ Eden ์ ํ ๋น
๋ฉ๋ชจ๋ฆฌ:
[Eden]
Customer ("Alice") โ ์ ๊ฐ์ฒด ์์น
[S0] (๋น์ด์์)
[S1] (๋น์ด์์)
[Old] (๋ค๋ฅธ ๊ฐ์ฒด๋ค)
Eden ์ด ๊ฐ๋ ์ฐจ๋ฉด Minor GC ํธ๋ฆฌ๊ฑฐ:
Minor GC ์์:
1. Eden + S0 (๋๋ S1) ์ ์ด์์๋ ๊ฐ์ฒด ์๋ณ
2. S1 (๋๋ S0) ์ผ๋ก ๋ณต์ฌ
3. Eden, ์๋ณธ Survivor ๋น์
์์:
Before Minor GC:
[Eden] Object A (Live), Object B (Garbage), Object C (Live)
[S0] (๋น์ด์์)
[S1] (๋น์ด์์)
After Minor GC:
[Eden] (๋น์ด์์)
[S0] (๋น์ด์์)
[S1] Object A (age=1), Object C (age=1) โ 1์ฐจ ์์กด
โ Object B ๋ Garbage โ ์ฌ๋ผ์ง.
๋ค์ Minor GC:
Before:
[Eden] Object D, Object E, Object F (๋ชจ๋ Live)
[S0] (๋น์ด์์)
[S1] Object A (age=1), Object C (age=1)
GC ์งํ:
[Eden + S1] โ S0 ์ผ๋ก ๋ณต์ฌ (๋ฐฉํฅ ๋ฐ๋!)
After:
[Eden] (๋น์ด์์)
[S0] Object A (age=2), Object C (age=2),
Object D (age=1), Object E (age=1), Object F (age=1)
[S1] (๋น์ด์์)
ํต์ฌ:
๊ฐ์ฒด์ age ๊ฐ Tenuring Threshold (๊ธฐ๋ณธ 15) ๋๋ฌ:
Object A ๊ฐ 15ํ ์ด์๋จ์:
[S0] Object A (age=15) โ Threshold ๋๋ฌ!
โ Promotion
[Old] Object A
[S0] ๋น์
Tenuring Threshold:
-XX:MaxTenuringThreshold=15Old ์์ญ์ด ๊ฐ๋ ์ฐจ๋ฉด:
Major GC (๋๋ Full GC):
1. Old ์ ์ด์์๋ ๊ฐ์ฒด ์๋ณ
2. Mark-Sweep-Compact ์งํ
3. ๋จํธํ ํด์
ํจ๊ณผ:
[ํ์]
โ
Eden โโMinor GCโโโ Survivor (age 1)
โ Minor GC
Survivor (age 2)
โ ... (15ํ)
โ
โโโPromotionโโโ Old
โ Major GC
(์๊ฑฐ)
๋์: Young Generation (Eden + Survivor)
๋น๋: ์์ฃผ (์ ์ด๋ง๋ค)
์๊ฐ: ๋น ๋ฆ (๋ณดํต ~10ms)
STW: ์งง์
์๊ณ ๋ฆฌ์ฆ: Copying GC
๊ด์ฐฐ ๊ฐ๋ฅ:
GC(0) Pause Young 25M->2M(64M) 5ms
๋์: Old Generation ๋ง
๋น๋: ๊ฐ๋ (๋ถ~์๊ฐ ๋จ์)
์๊ฐ: ๋๋ฆผ (์๋ฐฑ ms ~ ์ ์ด)
STW: ๊น (๋๋ Concurrent)
์๊ณ ๋ฆฌ์ฆ: Mark-Sweep-Compact (๋๋ Concurrent)
๊ด์ฐฐ ๊ฐ๋ฅ:
GC(50) Pause Old 100M->80M(150M) 500ms
๋์: Heap ์ ์ฒด (Young + Old + Metaspace)
๋น๋: ๋งค์ฐ ๊ฐ๋ (๋๋ ์๋์ ํธ๋ฆฌ๊ฑฐ)
์๊ฐ: ๋งค์ฐ ๋๋ฆผ (์ด ๋จ์)
STW: ๋งค์ฐ ๊น
์์ธ:
System.gc() ํธ์ถ๊ฒฝ๊ณ : Full GC ๊ฐ ์์ฃผ ๋ฐ์ = ๋ฉ๋ชจ๋ฆฌ ๋ฌธ์ โ ๏ธ
| Minor GC | Major GC | Full GC | |
|---|---|---|---|
| ๋์ | Young | Old | ์ ์ฒด |
| ๋น๋ | ์์ฃผ | ๊ฐ๋ | ๋งค์ฐ ๊ฐ๋ |
| ์๊ฐ | ๋น ๋ฆ (~ms) | ๋๋ฆผ (~์๋ฐฑ ms) | ๋งค์ฐ ๋๋ฆผ (~์ด) |
| STW | ์งง์ | ๊น | ๋งค์ฐ ๊น |
| ์๊ณ ๋ฆฌ์ฆ | Copying | Mark-Sweep-Compact | ๋ค์ |
| ๋ฐ์ ํธ๋ฆฌ๊ฑฐ | Eden ๊ฐ๋ | Old ๊ฐ๋ | ๋ค์ |
1๊ฐ๋ผ๋ฉด?:
2๊ฐ๋ก ์ด์:
ํจ๊ณผ:
โ Q1 ๋ต: Copying GC ํ์ฉ + ๋จํธํ ์๋ ํด์.
๊ฑฐ๋ ๊ฐ์ฒด = Survivor ์์ญ๋ณด๋ค ํฐ ๊ฐ์ฒด.
๋ฌธ์ :
ํด๊ฒฐ:
-XX:PretenureSizeThreshold=N[G1 Heap]
โโโ Eden Region
โโโ Survivor Region
โโโ Old Region
โโโ Humongous Region โ ํฐ ๊ฐ์ฒด
โ Q2 ๋ต: ์ง์ Old ํ ๋น ๋๋ Humongous ์์ญ.
// ์์ ์ํ:
// Eden: [A][B][C][D][E] (๋ชจ๋ ์ ๊ฐ์ฒด, B๋ Garbage)
// S0: (๋น์ด์์)
// S1: (๋น์ด์์)
// Old: [oldX][oldY]
Step 1: GC ํธ๋ฆฌ๊ฑฐ
Step 2: GC Root ์๋ณ
Step 3: ๋งํน (Reachability ๋ถ์)
Step 4: Copying โ ์ด์์๋ ๊ฐ์ฒด๋ฅผ S1 ๋ก
After:
Eden: (๋น์ด์์)
S0: (๋น์ด์์)
S1: [A age=1][C age=1][D age=1][E age=1]
Old: [oldX][oldY]
Step 5: STW ์ข ๋ฃ
Step 6: ๋ค์ GC
// Object A: age=14
// Tenuring Threshold = 15
// Minor GC ๋ฐ์:
// A ๊ฐ ์ด์๋จ์ โ age=15
// โ Threshold ๋๋ฌ!
// โ Old ๋ก Promotion
[Survivor]
[A age=15] โ ์ฌ๋ผ์ง
[Old]
[oldX][oldY][A] โ ์๋ก ๋ค์ด์ด
Adaptive Tenuring:
# ์กฐ์ ์ต์
-XX:MaxTenuringThreshold=15 # ์ต๋ 15ํ
-XX:TargetSurvivorRatio=50 # Survivor ๋ชฉํ 50%
๋ฌธ์ : Old โ Young ์ฐธ์กฐ๊ฐ ์์ผ๋ฉด Minor GC ์ Old ๋ ๋ด์ผ ํจ.
์์:
public class FareCache {
private static List<Fare> cache = new ArrayList<>(); // Old (long-lived)
public void add(Fare fare) { // fare ๋ Young
cache.add(fare);
// Old ๊ฐ์ฒด cache ๊ฐ Young ๊ฐ์ฒด fare ์ฐธ์กฐ
}
}
Card Table:
dirty ๋งํน:
// cache.add(fare) ์คํ ์ โ Write Barrier ๋ฐ์
// (JVM ์ด ์๋ ์ฒ๋ฆฌ)
// JVM:
// "cache ๊ฐ์ฒด๊ฐ fare (Young) ์ฐธ์กฐ ์ถ๊ฐ"
// โ cache ๊ฐ ์๋ ์นด๋๋ฅผ dirty ๋งํน
Minor GC ์:
1. Stack, static ์ GC Root ์ค์บ
2. dirty ์นด๋๋ง Old ์์ ์ถ๊ฐ ์ค์บ
3. ๋ชจ๋ Live ๊ฐ์ฒด ๋งํน
ํจ๊ณผ:
Write Barrier = ๊ฐ์ฒด ์ฐธ์กฐ ๋ณ๊ฒฝ ์ JVM ์ด ์๋ ์คํํ๋ ์ฝ๋.
์ญํ :
๋น์ฉ:
์ ํ์ ์ธ ์๋ฐ ์ ํ๋ฆฌ์ผ์ด์ :
Eden: ๋งค์ฐ ๋ง์ ๊ฐ์ฒด (์๋ง~์์ญ๋ง)
๋๋ถ๋ถ ๊ณง Garbage
S0/S1: ์ ์ ๊ฐ์ฒด (์๋ฐฑ~์์ฒ)
Eden ์ 1~10%
Old: ์ ๋นํ ๊ฐ์ฒด (์์ฒ~์๋ง)
์ด์๋จ์ ๊ฒ๋ค
๊ฐ์ฒด ์์ ๋ถํฌ:
โ ์ฝํ ์ธ๋ ๊ฐ์ค ์ ์ค์ ๋ชจ์ต.
๊ธฐ์กด ์ธ๋ ๊ตฌ์กฐ์ ์งํ โ G1 GC ๋ Region ๊ธฐ๋ฐ:
[Heap]
โโโ Region 0 (Eden)
โโโ Region 1 (Eden)
โโโ Region 2 (Survivor)
โโโ Region 3 (Old)
โโโ Region 4 (Humongous)
โโโ Region 5 (Free)
โโโ Region 6 (Eden)
โโโ Region 7 (Old)
โโโ ... (์๋ฐฑ ๊ฐ Region)
ํน์ง:
โ Unit 5.4 ์์ ์์ธํ.
public class GenerationDemo {
public static void main(String[] args) {
Runtime runtime = Runtime.getRuntime();
for (int i = 0; i < 1000; i++) {
// ์ ๊ฐ์ฒด โ Eden ์
byte[] data = new byte[1024 * 100]; // 100KB
if (i % 100 == 0) {
System.out.printf("Iteration %d, Free memory: %d MB%n",
i, runtime.freeMemory() / (1024 * 1024));
}
// i % 100 == 0 ์ผ ๋๋ง ์ด๋ ค๋ (๋ค๋ฅธ ์ปฌ๋ ์
์ ์ฐธ์กฐ)
if (i % 100 == 0) {
staticList.add(data); // Old ๋ก ๊ฐ๊ฒ ๋ง๋ฆ
}
}
}
private static List<byte[]> staticList = new ArrayList<>(); // GC Root
}
JVM ์ต์ ์ถ๊ฐ:
java -Xmx256m -Xms256m \
-Xlog:gc*:stdout:time,uptime,level,tags \
GenerationDemo
๊ด์ฐฐ:
java -Xms512m -Xmx512m \
-Xlog:gc*:file=gc.log:time,uptime,level,tags \
YourApp
๋ก๊ทธ ์์:
[0.150s] GC(0) Pause Young (G1 Evacuation Pause)
15M->5M(512M) 8.123ms
[1.234s] GC(1) Pause Young (G1 Evacuation Pause)
15M->6M(512M) 7.456ms
[5.678s] GC(2) Pause Young (G1 Mixed GC) โ Old๋ ์ผ๋ถ GC
50M->10M(512M) 25.123ms
[60.123s] GC(3) Pause Full (Allocation Failure)
200M->50M(512M) 350.456ms โ Full GC! โ ๏ธ
ํด์:
@Service
public class FareReportService {
// โ ๋ฉ๋ชจ๋ฆฌ ํญ๋ฐ ๊ฐ๋ฅ
public byte[] generateAllFaresReport() {
List<Fare> all = repository.findAll(); // 100๋ง ๊ฑด?
// โ Eden ํญ๋ฐ โ Survivor ๊ฑฐ์ณ Old ๊น์ง
// โ Heap ๊ฐ๋ โ OOM ๋๋ Full GC
return generatePdf(all);
}
// โ
Streaming
public void generateReportStream(OutputStream out) {
try (Stream<Fare> stream = repository.findAllAsStream()) {
stream.forEach(fare -> {
appendToPdf(out, fare);
// fare ๋ ์ฌ์ฉ ํ Eden ์ Garbage ๊ฐ ๋จ
// โ Minor GC ๋ก ๋น ๋ฅด๊ฒ ํ์
});
}
// ๋ฉ๋ชจ๋ฆฌ ์๋น ๊ฑฐ์ ์์
}
}
GC ์ธก๋ฉด:
@Component
public class FareCache {
private final Map<Long, Fare> cache = new ConcurrentHashMap<>();
@Scheduled(fixedRate = 1000) // 1์ด๋ง๋ค
public void refresh() {
List<Fare> recent = repository.findRecent();
recent.forEach(f -> cache.put(f.getId(), f));
// โ ๏ธ Fare ๋ค์ด ๊ณง๋ฐ๋ก Old ๋ก Promotion
// โ cache ๊ฐ GC Root ์ด๊ธฐ ๋๋ฌธ
// โ Old ์์ญ ๋น ๋ฅด๊ฒ ์ฐธ
// โ Major GC ๋น๋ฒ
}
}
๋ฌธ์ :
๊ฐ์ :
@Component
public class FareCache {
private final Cache<Long, Fare> cache =
Caffeine.newBuilder()
.expireAfterWrite(Duration.ofMinutes(5)) // ๋ง๋ฃ
.maximumSize(1000) // ํฌ๊ธฐ ์ ํ
.build();
// โ ์ ์ ํ ํฌ๊ธฐ ์ ์ง
// โ Old ์์ญ ์์
}
# JVM ์ต์
java -XX:+PrintTenuringDistribution \
-Xlog:gc*:stdout \
YourApp
์ถ๋ ฅ:
Desired survivor size 524288 bytes, new threshold 7 (max 15)
- age 1: 245664 bytes, 245664 total
- age 2: 156784 bytes, 402448 total
- age 3: 89456 bytes, 491904 total
- age 4: 45120 bytes, 537024 total โ ์ด๊ณผ!
ํด์:
โ Old ์์ญ ์๋ฐ ์ ํธ.
// โ static ์ปฌ๋ ์
โ Old ์ ๋ฌดํ ๋์
public class FareLogger {
private static List<String> logs = new ArrayList<>();
public static void log(String message) {
logs.add(LocalDateTime.now() + " - " + message);
// logs ๊ฐ ๋ฌดํ ์ฆ๊ฐ
}
}
GC ๊ด์ ์์์ ๋ฌธ์ :
ํด๊ฒฐ:
public class FareLogger {
private static final int MAX_SIZE = 1000;
private static final Deque<String> logs = new ArrayDeque<>(MAX_SIZE);
public static synchronized void log(String message) {
if (logs.size() >= MAX_SIZE) {
logs.pollFirst(); // ์ค๋๋ ๊ฒ ์ ๊ฑฐ
}
logs.addLast(LocalDateTime.now() + " - " + message);
}
}
@Service
public class FareCalculator {
// โ
์งง์ ์ผ์์ ๊ฐ์ฒด๋ง
public Money calculate(Fare fare, Customer customer) {
// ๋ชจ๋ ๋ฉ์๋ ์์์๋ง ์ฌ์ฉ โ Eden ์์ ์ฃฝ์
Money base = Money.of(fare.getAmount());
Money discount = base.multiply(customer.getDiscountRate())
.divide(100);
Money tax = base.subtract(discount).multiply(0.1);
return base.subtract(discount).add(tax);
}
}
GC ํจํด:
โ ์ฝํ ์ธ๋ ๊ฐ์ค ์ ๋ชจ๋ฒ ์ฌ๋ก.
Q: "๊ฐ์ฒด์ ์ผ์?"
A: "Eden โ Old ์
๋๋ค" โ
์ ๋ต: Eden โ Survivor (์ฌ๋ฌ ํ) โ Old
Survivor ๋ ํํฐ๋ง ์ญํ . ์ง์ง ์ฅ์ ๊ฐ์ฒด๋ง Old ๋ก.
Q: "Survivor ๊ฐ ๋ช ๊ฐ?"
A: "1๊ฐ์" โ
์ ๋ต: 2๊ฐ (S0, S1 ๋๋ From, To)
Copying GC ์ํด ๋์ด ๋ฒ๊ฐ์ ์ฌ์ฉ.
Q: "Major GC ์ Full GC ์ฐจ์ด?"
A: "๊ฐ์ ๊ฑฐ ์๋๊ฐ์?" โ
์ ๋ต:
์์ฃผ ํผ์ฉ๋์ง๋ง ์๋ฐํ๋ ๋ค๋ฆ.
Q: "๊ฐ์ฒด๊ฐ Old ๋ก ๊ฐ๋ ์กฐ๊ฑด?"
A: "15ํ ์ด์๋จ์ผ๋ฉด" โ (๋ถ์ ํ)
์ ๋ต:
for (int i = 0; i < Integer.MAX_VALUE; i++) {
Fare fare = new Fare();
fares.add(fare); // โ ๏ธ ๋์
}
๋ฌธ์ :
ํด๊ฒฐ: ์ฒ๋ฆฌ ํ ์ฐธ์กฐ ๋๊ธฐ, Stream ์ฌ์ฉ ๋ฑ.
java -Xmx2g -XX:NewSize=1g # Young 1GB
# ๊ทธ๋ฐ๋ฐ SurvivorRatio ๋ ๊ธฐ๋ณธ 8
# โ Eden 800MB, S0/S1 ๊ฐ 100MB
๊ฐ๋ฅํ ๋ฌธ์ :
ํ๋ ์ ๊ณ ๋ ค:
-XX:SurvivorRatio=8 # Eden:S0:S1 = 8:1:1 (๊ธฐ๋ณธ)
-XX:SurvivorRatio=4 # Eden:S0:S1 = 4:1:1 (Survivor ๋ ํผ)
์ด์: Full GC ๊ฐ ๋งค ๋ถ๋ง๋ค ๋ฐ์
๊ฐ๋ฐ์: "GC ์ ๋๊ณ ์๋ค"
์ง์ค: Full GC ๋ ์ํ ์ ํธ โ ๏ธ
์ ์:
๋งค ๋ถ Full GC = ๋ฉ๋ชจ๋ฆฌ ๋์ ๊ฐ๋ฅ์ฑ ๋์.
[Unit 5.1: GC ๊ธฐ๋ณธ + ์ฝํ ์ธ๋ ๊ฐ์ค] โ
โ
[Unit 5.2: Heap ์ ์ธ๋ ๊ตฌ์กฐ] โ ์ง๊ธ ์ฌ๊ธฐ โ
โ
[Unit 5.3: GC ์๊ณ ๋ฆฌ์ฆ 4๊ฐ์ง]
โ
[Unit 5.4: GC ์ข
๋ฅ์ ์ ํ ๊ธฐ์ค]
| ํ์ต | ์ธ๋ ๊ตฌ์กฐ ๊ด์ |
|---|---|
| Unit 4.1 (Heap) | ์ธ๋ ๊ตฌ์กฐ์ ๋ฌด๋ |
| Unit 4.2 (Pass by Value) | ๊ฐ์ฒด ์ฐธ์กฐ โ ์ธ๋ ์ถ์ |
| Unit 5.1 (์ฝํ ์ธ๋ ๊ฐ์ค) | ์ธ๋ ๊ตฌ์กฐ์ ์ด์ |
โ Phase 4-5 ๊ฐ ์์ฐ์ค๋ฝ๊ฒ ์ฐ๊ฒฐ.
5์ฃผ์ฐจ (Spring DI):
11-12์ฃผ์ฐจ (JPA):
13-14์ฃผ์ฐจ (DB/Cache):
4์ฃผ์ฐจ (๋์์ฑ):
# Heap ํฌ๊ธฐ
-Xms2g -Xmx2g # ์ด๊ธฐ/์ต๋ Heap
# Young ํฌ๊ธฐ
-Xmn800m # Young 800MB
-XX:NewRatio=2 # Young : Old = 1 : 2
-XX:NewSize=400m # Young ์ด๊ธฐ
-XX:MaxNewSize=800m # Young ์ต๋
# Survivor ๋น์จ
-XX:SurvivorRatio=8 # Eden : S = 8 : 1 (๊ธฐ๋ณธ)
# Promotion
-XX:MaxTenuringThreshold=15 # ์ต๋ 15ํ
-XX:TargetSurvivorRatio=50 # Survivor ๋ชฉํ 50%
# ๊ฑฐ๋ ๊ฐ์ฒด
-XX:PretenureSizeThreshold=1m # 1MB ์ด์์ ์ง์ Old
# ๋ชจ๋ํฐ๋ง
-XX:+PrintTenuringDistribution # ์ธ๋๋ณ ๋ถํฌ ์ถ๋ ฅ
-Xlog:gc* # GC ๋ก๊ทธ
| ์ง๋ฌธ | ์ด Unit์์์ ๋ต |
|---|---|
| "๊ฐ์ฒด์ ์ผ์?" | Eden โ Survivor (15ํ) โ Old |
| "Survivor ๊ฐ 2๊ฐ์ธ ์ด์ ?" | Copying GC + ๋จํธํ ํด์ |
| "Minor vs Major vs Full GC?" | ๋์ ์์ญ๊ณผ ๋น๋/์๊ฐ ์ฐจ์ด |
| "Promotion ์ด ๋ญ๊ฐ์?" | Tenuring Threshold ๋๋ฌ ์ Old ์ด๋ |
| "๊ฑฐ๋ ๊ฐ์ฒด ์ฒ๋ฆฌ?" | ์ง์ Old ๋๋ Humongous (G1) |
| "Card Table?" | Old โ Young ์ฐธ์กฐ ์ถ์ |
1๏ธโฃ Heap์ Young (Eden + S0 + S1) ๊ณผ Old ๋ก ๋๋๋ค.
์ฝํ ์ธ๋ ๊ฐ์ค์ ํ์ฉํด ๊ฐ์ฒด์ ์๋ช ์ ๋ฐ๋ผ ์์ญ ๋ถ๋ฆฌ. Young ๋น์จ ๋ณดํต 1/3, Eden:S0:S1 = 8:1:1. Eden ์ ์ ๊ฐ์ฒด โ Minor GC ์ ์ด์๋จ์ผ๋ฉด Survivor โ ์ผ์ ํ์ ์ด์๋จ์ผ๋ฉด Old ๋ก Promotion. ์ด ๊ตฌ์กฐ๊ฐ ์ฝํ ์ธ๋ ๊ฐ์ค์ ์ ํํ ๊ตฌํ.
2๏ธโฃ Survivor๊ฐ 2๊ฐ์ธ ๊ฒ์ Copying GC ๋ฅผ ์ํจ์ด๋ค.
ํ์ชฝ (From) ์ ์ฌ์ฉ, ๋ค๋ฅธ ์ชฝ (To) ์ ๋น์ด์์. Minor GC ์ [Eden + From] ์ ์ด์์๋ ๊ฐ์ฒด๋ฅผ [To] ๋ก ๋ณต์ฌ ํ ์๋ณธ ๋น์. ๋ค์์๋ ์ญํ ๋ฐ๋. ์๋ ์์ถ ํจ๊ณผ + ๋จํธํ ํด์. ๊ฐ์ฒด์ age ๊ฐ MaxTenuringThreshold (๊ธฐ๋ณธ 15) ๋๋ฌ ์ Old ๋ก Promotion.
3๏ธโฃ Minor GC vs Major GC vs Full GC ๋ฅผ ์ ํํ ๊ตฌ๋ณํด์ผ ํ๋ค.
Minor GC = Young ๋ง (์์ฃผ, ๋น ๋ฆ, ~ms), Major GC = Old ๋ง (๊ฐ๋, ๋๋ฆผ, ~์๋ฐฑ ms), Full GC = ์ ์ฒด (๋งค์ฐ ๊ฐ๋, ๋งค์ฐ ๋๋ฆผ, ~์ด). Full GC ๊ฐ ์์ฃผ ๋ฐ์ = ๋ฉ๋ชจ๋ฆฌ ๋์ ์ ํธ โ ๏ธ. Card Table ๋ก Old โ Young ์ฐธ์กฐ๋ฅผ ์ถ์ ํด Minor GC ํจ์จ ์ ์ง. ๊ฑฐ๋ ๊ฐ์ฒด๋ ์ง์ Old ํ ๋น ๋๋ Humongous (G1).
Q1: Survivor ๊ฐ ๋ ๊ฐ (From, To) ๋ก ๋๋์ด ์๋ ์ด์ ๋?
ํ ์ค ๋ต: Copying GC ๋ฅผ ํ์ฉํ๊ธฐ ์ํด. ํ์ชฝ์ ํญ์ ๋น์ด์์ด ์ด์์๋ ๊ฐ์ฒด๋ฅผ ๊ทธ์ชฝ์ผ๋ก ๋ณต์ฌํ๋ฉด ์๋ ์์ถ + ๋จํธํ ํด์ ํจ๊ณผ.
์์ธ ์ค๋ช :
๋ง์ฝ Survivor ๊ฐ 1๊ฐ๋ผ๋ฉด:
[Eden] [Survivor]
์ ๊ฐ์ฒด ์ด์๋จ์ ๊ฐ์ฒด
Minor GC:
- Eden ์ ์ด์์๋ ๊ฐ์ฒด๋ฅผ Survivor ๋ก ๋ณต์ฌ?
- ๊ทธ๋ฐ๋ฐ Survivor ์์๋ ์ด๋ฏธ ๊ฐ์ฒด๋ค ์์
- โ ์ถฉ๋! ๋๋ ๋ณต์กํ ์์ถ ๋ก์ง ํ์
๋ฌธ์ :
[Eden] [Survivor 0 (From)] [Survivor 1 (To)]
์ ๊ฐ์ฒด ํ์ฌ ๊ฑฐ์ฃผ ๋น์ด์์
Minor GC ์:
1. [Eden + Survivor 0] ์ ์ด์์๋ ๊ฐ์ฒด ์๋ณ
2. ๋ชจ๋ [Survivor 1] ๋ก ๋ณต์ฌ
3. [Eden] ๋น์
4. [Survivor 0] ๋น์
After:
[Eden] [Survivor 0] [Survivor 1]
๋น์ ๋น์ ํ์ฌ ๊ฑฐ์ฃผ
๋ค์ Minor GC:
1. [Eden + Survivor 1] โ [Survivor 0]
2. ์ญํ ๋ฐ๋!
ํต์ฌ ํจ๊ณผ โญ :
์๋ (๊ฐ์ฒด) ์ด ํธํ ์ ๋จธ๋ฌด๋ ์ํฉ:
1๊ฐ ๋ฐฉ๋ง ์๋ค๋ฉด:
2๊ฐ ๋ฐฉ ์๋ค๋ฉด (์๋ฐ ๋ฐฉ์):
โ ๊ฐ๋จํ๊ณ ํจ์จ์ .
"Survivor ๊ฐ 2๊ฐ์ธ ๊ฒ์ Copying GC ์ ์์ฐ์ค๋ฌ์ด ์๊ตฌ.
ํ ์์ญ์์ ๋ค๋ฅธ ์์ญ์ผ๋ก์ ๋จ์ ๋ณต์ฌ๊ฐ ๊ฐ์ฅ ํจ์จ์ ์ด๊ณ ,
์๋ ์์ถ ํจ๊ณผ + ๋จํธํ ํด์ ๋ผ๋ ๋ถ์ ํจ๊ณผ๊น์ง."
Q2: ๊ฑฐ๋ ๊ฐ์ฒด (Survivor ์์ญ๋ณด๋ค ํฐ) ๋ ์ด๋ป๊ฒ ์ฒ๋ฆฌ๋๋๊ฐ?
ํ ์ค ๋ต: ์ง์ Old ์์ญ์ ํ ๋น ๋๋ Humongous Region (G1 GC).
์์ธ ์ค๋ช :
byte[] hugeArray = new byte[100 * 1024 * 1024]; // 100MB
๊ฑฐ๋ ๊ฐ์ฒด = Survivor ์์ญ๋ณด๋ค ํฐ ๊ฐ์ฒด.
์ ๋ฌธ์ ์ธ๊ฐ?:
JVM ์ต์ :
-XX:PretenureSizeThreshold=1m # 1MB ์ด์์ ์ง์ Old
๋์:
byte[] huge = new byte[10 * 1024 * 1024]; // 10MB
// Eden ๊ฑฐ์น์ง ์๊ณ โ Old ์ง์ ํ ๋น
ํจ๊ณผ:
๋จ์ :
G1 GC ๋ Region ๊ธฐ๋ฐ:
[Heap]
โโโ Region 0 (Eden, 1MB)
โโโ Region 1 (Eden, 1MB)
โโโ Region 2 (Survivor, 1MB)
โโโ Region 3 (Old, 1MB)
โโโ Region 4 (Humongous, 1MB) โ ํฐ ๊ฐ์ฒด
โโโ ... ์๋ฐฑ ๊ฐ
Humongous Object ์ ์:
์์:
Region ํฌ๊ธฐ 1MB
๊ฐ์ฒด ํฌ๊ธฐ 3MB
โ Humongous Region ์ผ๋ก 3๊ฐ ์ฐ์ ์ฌ์ฉ
JVM ์ต์ :
-XX:G1HeapRegionSize=4m # Region 4MB
ํจ๊ณผ:
์ํฉ: ์ด์ ๋ณด๊ณ ์ PDF ์์ฑ
@Service
public class FareReportService {
public byte[] generateMonthlyReport() {
// 100MB PDF ์์ฑ?
byte[] pdfData = generatePdf(...); // ๊ฑฐ๋ ๊ฐ์ฒด
return pdfData;
}
}
๋ฌธ์ :
ํด๊ฒฐ:
1. Streaming:
public void streamReport(OutputStream out) {
generatePdfStream(out); // ๋ฉ๋ชจ๋ฆฌ์ ๋ค ์ ์ฌ๋ฆผ
}
Pretenuring:
G1 + Humongous:
"๊ฑฐ๋ ๊ฐ์ฒด๋ ์ผ๋ฐ ๊ฐ์ฒด์ ๋ค๋ฅธ ๊ฒฝ๋ก๋ก ์ฒ๋ฆฌ.
Pretenuring (์ง์ Old) ๋๋ G1์ Humongous Region.
๊ฐ๋ฅํ๋ฉด Streaming ๋ฑ์ผ๋ก ๊ฑฐ๋ ๊ฐ์ฒด ์์ฒด๋ฅผ ๋ง๋ค์ง ์๋ ๊ฒ์ด ์ต์ ."















