Java & Kotlin

[JVM] G1 GC의 보충설명

해당 글은 지난 글의 보충을 위해 작성한 글이며 6절과 7절에 대한 내용의 보충을 위해 쓴 글이다6. Concurrent Mark는 언제 시작되는가?G1 GC는 평소에는 Young GC를 반복해서 수행한다.Normal Young GC ↓Normal Young GC ↓Normal Young GC하지만 Old 영역의 사용량이 계속 증가하면 언젠가는 Old 영역도 회수해야 한다.이때 G1은 Old 영역이 완전히 가득 찬 뒤에 움직이는 것이 아니라, 미리 Concurrent Mark를 시작한다.Concurrent Mark를 시작할 시점을 판단하는 기준이 IHOP(Initiating Heap Occupancy Percent) 이다.초기에는 기본값을 기준으로 판단하지만, 일반적으로 G1은 ..

2026. 9. 9. 21:20·waterboom

Java & Kotlin

[JVM] G1 GC

지난 글의 이야기를 한 문단으로 접어두고 시작하자. Full GC의 긴 멈춤 앞에서 두 갈래 길이 있었다. 멈춘 동안 여럿이 달려들어 빨리 끝내자는 쪽은 Parallel GC가 됐고 아예 멈추지 말자는 쪽은 삼색 마킹과 배리어로 동시 마킹까지 해냈다. 하지만 그 첫 제품인 CMS는 객체 이동을 포기한 대가로 단편화에 무너졌다. 그로 인해 얻을 수 있었던 것은 "압축을 버리면 안 된다" 라는 것이다. 그렇다면 남은 것은 하나다. 압축을 버리지 않으면서 긴 멈춤도 피하려면 어떻게 해야 할까. 그 답을 들고 나온 GC가 G1이다. 이번 글은 G1 하나만 깊게 판다.1. Region (논문 2004, JDK 9 기본) — 힙을 2048조각으로먼저 모순을 정리해보자. 압축은 해야 한다. 하지만 힙 전체 압축에는 ..

2026. 9. 2. 21:54·waterboom

Java & Kotlin

[JVM] GC 알고리즘의 역사

0. 문제의 탄생 — 수동 메모리 관리C에서 힙 메모리는 사람이 직접 반납한다.char *buf = malloc(1024);...free(buf); // 잊으면 → 누수 (프로세스가 살아있는 한 계속 샘)free(buf); // 실수로 한 번 더 → 힙 자료구조 파괴, 크래시 or 보안 취약점use(buf); // 해제 후 사용 → 댕글링 포인터, 그 자리에 뭐가 들었을지 모름셋 다 컴파일러가 못 잡아준다. 같은 메모리를 가리키는 포인터가 여러 개일 수 있어서 "이 시점 이후 아무도 안 쓴다"를 증명할 수 없기 때문이다. 그래서 나온 결론이 이것이다. "객체가 더 이상 안 쓰이는 시점"을 판정하는 일 자체를 아예 기계에게 넘겨버리자. 이게 GC다. 그런데 문제는 기계가 그걸 ..

2026. 9. 1. 23:20·waterboom

Java & Kotlin

[JVM] JIT(Just-In-Time) 컴파일러의 발전과정 알아보기 - 1

"자바는 느리다."한 번쯤 들어봤을 말이다. 그런데 요즘 자바로 짠 서버가 느려서 문제가 되는 경우는 별로 없다. 언어 문법이 크게 바뀐 것도 아닌데, 그 사이에 무슨 일이 있었던 걸까?그 간극을 메운 것이 바로 JIT 컴파일러다.JIT 컴파일러란?JIT(Just-In-Time) 컴파일러는 프로그램이 실행되는 도중에, 자주 실행되는 코드를 네이티브 기계어로 번역해 두고 재사용하는 컴파일러다.번역을 "미리" 하지도, "매번" 하지도 않고 필요한 순간에(just in time) 한다는 것이 이름의 뜻이다.방식번역 시점특징컴파일 (AOT)실행 전에 전부빠르지만 플랫폼마다 다시 컴파일해야 함인터프리터실행하면서 매번이식성은 좋지만 느림JIT실행 중, 자주 쓰이는 부분만인터프리터로 시작해 뜨거운 코드만 기계어로말로..

2026. 8. 27. 16:23·waterboom