"JVM์ ๋ฉ๋ชจ๋ฆฌ ๊ตฌ์กฐ์ ๊ฐ๋น์ง ์ปฌ๋ ์ ์ ๋์ ๋ฐฉ์์ ๋ํด ์ค๋ช ํด์ฃผ์ธ์. ๊ฐ GC ์๊ณ ๋ฆฌ์ฆ์ ์ฅ๋จ์ ์ ๋ฌด์์ธ๊ฐ์?"
public class HeapStructure {
// Young Generation
// - Eden
// - Survivor 0
// - Survivor 1
// Old Generation
public static void main(String[] args) {
// Eden ์์ญ์ ๊ฐ์ฒด ์์ฑ
Object obj = new Object();
// ํฐ ๊ฐ์ฒด๋ ๋ฐ๋ก Old Generation์ผ๋ก
byte[] bigArray = new byte[1024 * 1024 * 10]; // 10MB
}
}
public class NonHeapStructure {
// Method Area (Metaspace in Java 8+)
static final String CONSTANT = "This is constant";
// Stack
public void stackExample() {
int localVar = 42; // Stack์ ์ ์ฅ
Object obj = new Object(); // ์ฐธ์กฐ๋ Stack, ๊ฐ์ฒด๋ Heap
}
}
// Serial GC ์ฌ์ฉ ์ค์
// -XX:+UseSerialGC
public class SerialGCExample {
public static void main(String[] args) {
System.out.println("GC Algorithm: " +
ManagementFactory.getGarbageCollectorMXBeans()
.stream()
.map(GarbageCollectorMXBean::getName)
.collect(Collectors.joining(", ")));
}
}
// Parallel GC ์ค์
// -XX:+UseParallelGC
// -XX:ParallelGCThreads=4
public class ParallelGCExample {
private static final int MB = 1024 * 1024;
public static void main(String[] args) {
List<byte[]> list = new ArrayList<>();
for (int i = 0; i < 100; i++) {
list.add(new byte[MB]); // ๋ฉ๋ชจ๋ฆฌ ํ ๋น
}
}
}
// G1 GC ์ค์
// -XX:+UseG1GC
// -XX:MaxGCPauseMillis=200
public class G1GCExample {
public static void main(String[] args) {
// G1 GC ๋ชจ๋ํฐ๋ง
for (GarbageCollectorMXBean gc :
ManagementFactory.getGarbageCollectorMXBeans()) {
long count = gc.getCollectionCount();
long time = gc.getCollectionTime();
String name = gc.getName();
System.out.printf("GC %s: %d collections, %dms%n",
name, count, time);
}
}
}
# GC ๋ก๊น
์ต์
-verbose:gc
-Xlog:gc*:file=gc.log
-XX:+PrintGCDetails
-XX:+PrintGCDateStamps
public class MemoryLeakDetector {
private static final List<Object> leakyList = new ArrayList<>();
public static void detectLeak() {
MemoryMXBean memoryBean = ManagementFactory.getMemoryMXBean();
MemoryUsage heapUsage = memoryBean.getHeapMemoryUsage();
System.out.printf("Memory used: %d MB%n",
heapUsage.getUsed() / 1024 / 1024);
if ((double) heapUsage.getUsed() / heapUsage.getMax() > 0.8) {
System.out.println("Potential memory leak detected!");
}
}
}
# ํ ํฌ๊ธฐ ์ค์
-Xms4g # ์ด๊ธฐ ํ ํฌ๊ธฐ
-Xmx4g # ์ต๋ ํ ํฌ๊ธฐ
-XX:MetaspaceSize=256m
-XX:MaxMetaspaceSize=256m
# G1 GC ํ๋
-XX:+UseG1GC
-XX:MaxGCPauseMillis=200
-XX:G1HeapRegionSize=8m
-XX:InitiatingHeapOccupancyPercent=45
-
"์ค์ ํ๋ก๋์ ํ๊ฒฝ์์ GC ํ๋์ ํด๋ณด์ ๊ฒฝํ์ด ์๋์?"
-
"๋ฉ๋ชจ๋ฆฌ ๋ฆญ์ ๋ฐ๊ฒฌํ๊ณ ํด๊ฒฐํ ๊ฒฝํ์ ์ค๋ช ํด์ฃผ์ธ์."
-
"์ด๋ค GC ์๊ณ ๋ฆฌ์ฆ์ ์ ํธํ์๋์? ๊ทธ ์ด์ ๋?"
-
"GC ๋ก๊ทธ๋ฅผ ์ด๋ป๊ฒ ๋ถ์ํ์๋์?"
public class GCMonitor {
public static void monitorGC() {
List<GarbageCollectorMXBean> gcBeans =
ManagementFactory.getGarbageCollectorMXBeans();
for (GarbageCollectorMXBean gcBean : gcBeans) {
System.out.println(gcBean.getName());
System.out.println("Collection Count: " +
gcBean.getCollectionCount());
System.out.println("Collection Time: " +
gcBean.getCollectionTime() + "ms");
}
}
}
@Component
@Slf4j
public class MemoryMonitor {
@Scheduled(fixedRate = 60000) // 1๋ถ๋ง๋ค ์คํ
public void checkMemory() {
Runtime runtime = Runtime.getRuntime();
long totalMemory = runtime.totalMemory();
long freeMemory = runtime.freeMemory();
long usedMemory = totalMemory - freeMemory;
log.info("Memory Usage: {}MB / {}MB",
usedMemory/1024/1024,
totalMemory/1024/1024);
}
}
์ค์ ๋ฉด์ ์์๋ ์ด๋ก ์ ์ธ ์ง์๊ณผ ํจ๊ป GC ํ๋ ๊ฒฝํ, ๋ฉ๋ชจ๋ฆฌ ๋ฌธ์ ํด๊ฒฐ ๊ฒฝํ, ์ฑ๋ฅ ์ต์ ํ ๊ฒฝํ ๋ฑ์ ๊ตฌ์ฒด์ ์ผ๋ก ์ค๋ช ํ๋ ๊ฒ์ด ์ข์ต๋๋ค.
-
Young Generation (Minor GC)
1. Eden ์์ญ์์ ๊ฐ์ฒด ์์ฑ 2. Eden ์์ญ์ด ๊ฐ๋ ์ฐจ๋ฉด GC ๋ฐ์ 3. ์ด์์๋ ๊ฐ์ฒด๋ฅผ Survivor ์์ญ์ผ๋ก ์ด๋ 4. Eden ์์ญ์ ๋น์
-
Old Generation (Major GC)
1. Mark-Sweep-Compact ์๊ณ ๋ฆฌ์ฆ ์ฌ์ฉ 2. Mark: ์ด์์๋ ๊ฐ์ฒด ์๋ณ 3. Sweep: ์ฃฝ์ ๊ฐ์ฒด ์ ๊ฑฐ 4. Compact: ์ด์์๋ ๊ฐ์ฒด๋ค์ ํ์ชฝ์ผ๋ก ๋ชจ์
- ์ฅ์ :
- ๋จ์ํ ์๊ณ ๋ฆฌ์ฆ์ผ๋ก ๊ตฌํ์ด ๊ฐ๋จ
- ์ฑ๊ธ ์ค๋ ๋ ํ๊ฒฝ์์ ํจ์จ์
- ์์ ๋ฉ๋ชจ๋ฆฌ์์ ํจ๊ณผ์
- ๋จ์ :
- Stop-the-World ์๊ฐ์ด ๊น
- ๋ฉํฐ์ฝ์ด ํ๊ฒฝ์์ ๋นํจ์จ์
- ํฐ ํ ๋ฉ๋ชจ๋ฆฌ์์ ์ฑ๋ฅ ์ ํ
-
Young Generation
1. ์ฌ๋ฌ ์ค๋ ๋๊ฐ ๋์์ GC ์ํ 2. Eden ์์ญ์ ์ด์์๋ ๊ฐ์ฒด๋ค์ ๋ณ๋ ฌ๋ก Survivor๋ก ์ด๋ 3. ๋น Eden ์์ญ์ ํ ๋ฒ์ ๋น์
-
Old Generation
1. Mark ๋จ๊ณ: ์ฌ๋ฌ ์ค๋ ๋๊ฐ ๋์์ ์ด์์๋ ๊ฐ์ฒด ํ์ 2. Sweep ๋จ๊ณ: ๋ณ๋ ฌ๋ก ์ฃฝ์ ๊ฐ์ฒด ์ ๊ฑฐ 3. Compact ๋จ๊ณ: ์ด์์๋ ๊ฐ์ฒด๋ค์ ๋ณ๋ ฌ๋ก ์ฌ๋ฐฐ์น
- ์ฅ์ :
- Minor GC, Major GC ๋ชจ๋ ๋ณ๋ ฌ ์ฒ๋ฆฌ๋ก ๋น ๋ฅธ ์ฒ๋ฆฌ
- ๋์ ์ฒ๋ฆฌ๋(Throughput)
- ๋ฉํฐ์ฝ์ด ํ๊ฒฝ์์ ํจ์จ์
- ๋จ์ :
- Stop-the-World ์๊ฐ์ ์ฌ์ ํ ์กด์ฌ
- ๋ฉ๋ชจ๋ฆฌ์ CPU ์ฌ์ฉ๋์ด ์ฆ๊ฐ
- ์ผ์ ์ ์ง ์๊ฐ์ด ์์ธก ๋ถ๊ฐ๋ฅ
1. Initial Mark (STW)
- GC Root์์ ์ง์ ์ฐธ์กฐํ๋ ๊ฐ์ฒด๋ง ๋งํน
2. Concurrent Mark
- ์ ํ๋ฆฌ์ผ์ด์
์คํ๊ณผ ๋์์ ๋งํน
- ์ฐธ์กฐ๋ ๊ฐ์ฒด๋ค์ ์ถ์
3. Remark (STW)
- Concurrent Mark ๋จ๊ณ์์ ๋ณ๊ฒฝ๋ ๋ถ๋ถ ํ์ธ
- ์ต์ข
๋งํน ์์
4. Concurrent Sweep
- ์ ํ๋ฆฌ์ผ์ด์
์คํ๊ณผ ๋์์ ๊ฐ๋น์ง ์ ๊ฑฐ
- ์ฅ์ :
- Stop-the-World ์๊ฐ์ด ๋งค์ฐ ์งง์
- ์๋ต ์๊ฐ(Latency)์ด ์ค์ํ ์ ํ๋ฆฌ์ผ์ด์ ์ ์ ํฉ
- ์ค์๊ฐ ์ฒ๋ฆฌ๊ฐ ํ์ํ ์์คํ ์ ์ ํฉ
- ๋จ์ :
- CPU์ ๋ฉ๋ชจ๋ฆฌ ์ฌ์ฉ๋์ด ๋์
- ๋ฉ๋ชจ๋ฆฌ ๋จํธํ ๋ฌธ์ ๋ฐ์
- Compaction ๊ณผ์ ์ด ์์
1. Young GC
1) Eden ์์ญ์ ์ด์์๋ ๊ฐ์ฒด๋ฅผ Survivor ์์ญ์ผ๋ก ์ด๋
2) ์ฌ๋ฌ ์ค๋ ๋๊ฐ ๋ณ๋ ฌ๋ก ์์
2. Mixed GC
1) Initial Mark (STW)
- GC Root ์ค์บ
2) Concurrent Mark
- ์ ์ฒด ํ์ ์ด์์๋ ๊ฐ์ฒด ์ถ์
3) Remark (STW)
- ์ต์ข
๋งํน ์์
4) Cleanup (STW/Concurrent)
- ๋น ๋ฆฌ์ ํ์ ๋ฐ ํ์ํ ๋ฆฌ์ ๊ณ์ฐ
- ์ฅ์ :
- ํฐ ํ ๋ฉ๋ชจ๋ฆฌ์์๋ ํจ์จ์
- ์์ธก ๊ฐ๋ฅํ Stop-the-World ์๊ฐ
- ๋ฉ๋ชจ๋ฆฌ ๋จํธํ ์ต์ํ
- Region ๋จ์์ ๋ฉ๋ชจ๋ฆฌ ๊ด๋ฆฌ๋ก ์ ์ฐํจ
- ๋จ์ :
- CPU์ ๋ฉ๋ชจ๋ฆฌ ์ฌ์ฉ๋์ด ๋ ๋์
- ๋ณต์กํ ์๊ณ ๋ฆฌ์ฆ์ผ๋ก ์ธํ ํ๋์ ์ด๋ ค์
- ์์ ํ์์๋ ์ค๋ฒํค๋ ๋ฐ์
1. Mark Start (STW - ฮผs ๋จ์)
- GC Root์์ ์์ํ๋ ๊ฐ์ฒด ๋งํน ์์
2. Concurrent Mark and Remap
- ์ ํ๋ฆฌ์ผ์ด์
์คํ๊ณผ ๋์์ ๋งํน
- ๋ฉ๋ชจ๋ฆฌ ํ์ด์ง ์ฌ๋งคํ
3. Mark End (STW - ฮผs ๋จ์)
- ๋งํน ์์
์๋ฃ
4. Concurrent Reset and Remap
- ๋ฉ๋ชจ๋ฆฌ ์ ๋ฆฌ ๋ฐ ์ฌ๊ตฌ์ฑ
- ์ฅ์ :
- ๋งค์ฐ ์งง์ Stop-the-World ์๊ฐ(< 10ms)
- ํฐ ํ ํฌ๊ธฐ(์ TB)์์๋ ํจ์จ์
- ๋ฉ๋ชจ๋ฆฌ ๋จํธํ ๋ฌธ์ ํด๊ฒฐ
- ๋จ์ :
- ๋ ๋์ CPU์ ๋ฉ๋ชจ๋ฆฌ ์ฌ์ฉ๋
- ์์ง ์์ ํ ๋จ๊ณ
- ๋ฉ๋ชจ๋ฆฌ ์ค๋ฒํค๋ ์กด์ฌ
์ด๋ฌํ ๊ฐ GC์ ํน์ฑ์ ์ดํดํ๊ณ ์ ํ๋ฆฌ์ผ์ด์ ์ ์๊ตฌ์ฌํญ(์๋ต์๊ฐ, ์ฒ๋ฆฌ๋, ๋ฉ๋ชจ๋ฆฌ ํฌ๊ธฐ ๋ฑ)์ ๋ง๋ ์ ์ ํ GC๋ฅผ ์ ํํ๋ ๊ฒ์ด ์ค์ํฉ๋๋ค.