이 포스팅을 보기 앞서 Java의 메모리/데이터 영역을 모른다면 ➡ [클릭]
c,c++ 에서는 코드에서 직접 메모리를 할당 받고, 해제해야 한다. 하지만 자칫 실수하면 Memory Leak이 발생하고, 메모리를 매번 수동으로 할당/해제하는 것은 번거롭다.
하지만 Java에서는 GC가 직접 Heap 영역을 자동으로 할당/해제 해주어 더 편리하고, 안정적이다.
GC는 힙 메모리 영역만 다룬다.
GC에 대해서 알아보기 전에 'stop-the-world'라는 용어를 알아야 한다. 'stop-the-world'란, GC를 실행하기 위해 JVM이 애플리케이션 실행을 멈추는 것이다.
프로세스는 Marking을 호출하고, GC가 메모리가 사용되는지 아닌지를 찾아낸다. 모든 오브젝트는 마킹 단계에서 결정을 위해 스캔되어집니다. 모든 오브젝트를 스캔하기 때문 에 매우 많은 시간을 소모하게 됩니다.
참조되지 않는 객체를 제거하고, 메모리를 반환한다. 메모리 Allocator는 반환되어 비어진 블럭의 참조 위치를 저장해 두었다고 새로운 오브젝트가 선언되면 할당되도록 한다.
퍼포먼스를 향상시키기 위해, 참조되지 않는 객체를 제거하고 또한 남은 참조되어지는 객체들을 묶는다.
하지만 위와 같이 모든 Heap영역을 GC가 스캔하는 것은 상당히 비효율적이다. 따라서 Weak Generational Hypothesis라는 가설을 바탕으로 현재는 Heap 영역을 세부 영역으로 나누어 GC가 스캔한다.
☑ Referenced Object vs Not Referenced Object
- Method가 실행되는 동안 로컬 변수는 Stack 영역에 저장
- Stack영역의 로컬 변수는 Heap 영역의 객체(Object)를 참조하고 있고(로컬 변수에는 주소가 저장되었다는 뜻), 그 객체를 Referenced Object라고 함
- Method가 끝나면, 그 method에 해당하는 지역변수는 Stack에서 제거
- Heap에 있는 객체 중 Stack에서 자신을 참조하고 있는 변수가 없다면, Not Referenced Object라고 함
🔼Y축 할당된 바이트의 수, X축 바이트가 할당될 때의 시간
즉, 위 가설은 신규로 생성한 객체의 대부분은 금방 사용하지 않는 상태가 되고, 오래된 객체에서 신규 객체로의 참조는 매우 적게 존재한다는 가설이다.
이 가설에 기반하여 자바는 Young 영역과 Old 영역으로 메모리를 분할하고, 신규로 생성되는 객체는 Young 영역에 보관하고, 오랫동안 살아남은 객체는 Old 영역에 보관한다.
Young 영역(Yong Generation 영역)
새롭게 생성한 객체의 대부분이 여기에 위치합니다. 대부분의 객체가 금방 접근 불가능 상태가 되기 때문에 매우 많은 객체가 Young 영역에 생성되었다가 사라집니다. 이 영역에서 객체가 사라질때 Minor GC 가 발생한다고 말합니다.
Old 영역(Old Generation 영역)
접근 불가능 상태로 되지 않아 Young 영역에서 살아남은 객체가 여기로 복사됩니다. 대부분 Young 영역보다 크게 할당하며, 크기가 큰 만큼 Young 영역보다 GC는 적게 발생합니다. 이 영역에서 객체가 사라질 때 Major GC(혹은 Full GC) 가 발생한다고 말합니다.
Permanet 영역
Method Area라고도 합니다. JVM이 클래스들과 메소드들을 설명하기 위해 필요한 메타데이터들을 포함하고 있습니다. JDK8부터는 PermGen은 Metaspace로 교체됩니다.
minor gc이 시작된다.