Study/JAVA

Heap 영역과 GC(Garbage Collector) - JAVA

긷뚜 2021. 5. 10. 16:57
728x90

Heap Area

JVM Heap Area

특징

  • 자바에서의 heap 영역은 JVM 존재하는 Runtime Data Area 안에 존재한다.
  • heap 영역은 new 연산자 등으로 생성된 객체(인스턴스)와 배열 등이 저장되는 영역이다.
  • heqp 영역에 저장된 객체(인스턴스)나 배열은 다른 객체에서 참조 될 수 있다.
  • GC(Garbage Collector)가 발생 하는 영역이며, 참조(레퍼런스)가 없는 객체들은 GC과정을 통해 메모리에서 제거 된다.
  • 위의 그림과 같이 Heap 영역은 여러 여역으로 나뉘며 이는 객체의 LifeCycle 및 GC와 연관되어 있다.

Heap 영역에 객체가 적재되는 방법

public class Main{
    public static void main(String[] args){
        int n = 10;
        String name = "긷";
        Person p = new Person("긷", 26);
        name += "뚜";
       }
 }       

먼저 위 코드를 보자 main 함수의 1~3번째 줄을 보면 n = 10과 name그리고 p가 stack에 적재 될것이다.
그와 함께 "긷"의 정보와 Person 객체의 인스턴스("긷", 26)은 Heap에 적재 되고 stack에 name 과 p 는 "긷"과 ("긷",26)을 참조 할 것이다.

첫번째 문제가 여기서 나온다. 4번째 줄을 보면 name += "뚜" 라는 과정을 통해 "긷뚜"라는 새로운 String을 만들었고 이 값은 heap 영역에 적재되고 이 값은 name이 참조 할 것이다. 그럼 기존에 heap영역에 존재하던 "긷" 이라는 String은 어떠한 참조 없이 heap 영역에 존재하게 되는것이다.

두번째 문제는 main함수의 스코프가 끝나면서 나타난다. main함수가 끝나면 stack에 쌓여있던 모든 변수들이 차례로 빠진다.
그러면 heap영역에 존재하던 모든 데이터들은 어떠한 참조 없이 존재하게 된다.

이렇게 참조 없이 남아있는 메모리 들을 기존 C/C++ 에서는 사용자가 직접 해제해 줘야 했지만 JAVA 에서는 이렇게 남아있는 동적 메모리들을 JVM 상에존재하는 Exetution engine 안의 Garbage Collector가 해제해 준다.


Garbage Collector

Garbage Collector 과정

  • Garbage Collector(이하 GC)가 stack의 모든 변수를 스캑하면서 각각 어떤 객체(인스턴스)를 참조하고 있는지 찾아서 마킹한다.
  • 또 Heap 에서는 객체가 Garbage인지 판별 하기 위해 reachability라는 개념을 사용하는데 유효한 참조가 있으면 'reachable', 없다면 'unreachable' 로 구별하는데 이때 'reachable' 도 찾아서 마킹한다. 그리고 위 두 과정을 Mark 라고 한다.
  • 마킹되지 않은 객체 또 unreachable로 구별된 객체를 찾아 Heap 에서 제거한다. 그리고 이 과정을 Sweep 이라고 한다.
  • 이러한 일련의 과정을 Mark and Sweep이라고도 한다.

Garbage Collector의 일어나는 시기

JVM Heap Area

다시 Heap 영역을 보면 Young Generation과 Old Generation 으로 나뉘고 또 세부적인 영역이 있다.
이들은 GC와 밀접한 연관이 있으므로 하나씩 설명하고 가겠다.

Eden 영역(Young 영역)

새로 생성된 대부분의 객체(인스턴스)들이 처음으로 위치하는 영역이다. Eden 영역에서는 정기적으로 GC가 발생하고, 살아남은 객체들은 Survivor1 또는 Survivor2 중 선택된 하나의 영역으로만 이동하여 계속 쌓이게 된다.

Survivor1, Survivor2 영역(Young 영역)

Survivor 영역은 1, 2에 중점을 둘 것이 아닌 두 영역으로 나뉜다는것을 중점으로 보면 된다.
Eden영역에서 살아남은 객체 들은 Survivor1 또는 Survivor2 중 하나만 으로 이동하게 되고 만약 둘중 하나가 꽉찬다면 GC를 실행하고 살아남은 객체들은 다른 비어있는 Survivor 영영역으로 이동하게 된다.
이러한 매커니즘 때문에 Survivor 영역의 둘중 하나는 항상 비워진 상태가 되며 하나의 영역이 완전히 비어있지 않다면 문제가 있는 것이다.

Young 영역에서 발생하는 GC를 Minor GC 라고 한다.
Minor GC에서 살아남아 Survivor로 이동할 때마다 객체의 Age 가 증가하는데 이 Age가 일정 이상이 되면 Old 영역으로 이동하게 된다. 그리고 이것을 Promotion 이라고 한다.
Promotion의 기준이 되는 Age 값은 JAVA SE8 기준으로는 15 이면 이는 사용자가 임의로 조정할 수 있다(0~15)

Old 영역

Survivor1 또는 Survivor2 영역을 왔다갔다 하는 과정에서 끝까지 살아남은 객체는 Old영역으로 이동하게 된다. 보통 Old 영역은 Young 영역보다 크게 할당하며, Young 영역에 비해 GC 가 적게 발생한다

Old 영역에서 발생하는 GC를 Major GC(Full GC) 라고 한다.

JVM Heap 영역내에서 객체의 LifeCycle

Old 영역에 대한 GC

Old 영역은 기본적으로 데이터가 가득 차면 GC를 실행한다. GC 방식에 따라 처리 절차가 달라진다. 이는 JDK 7 을 기준으로 5가지 방식이 있다

Serial GC(-XX:+UseSerialGC)

Parallel GC(-XX:+UseParallelGC)

Parallel Old GC(-XX:+UseParallelOldGC)

CMS GC(-XX:++UseConcMarkSweepGC)

G1 GC


reference

https://docs.oracle.com/javase/8/docs/technotes/tools/windows/java.html
https://d2.naver.com/helloworld/1329
https://d2.naver.com/helloworld/329631
https://mirinae312.github.io/develop/2018/06/04/jvm_memory.html
https://yaboong.github.io/java/2018/06/09/java-garbage-collection/
https://www.youtube.com/watch?v=vZRmCbl871I&t=2s&ab_channel=%EC%9A%B0%EC%95%84%ED%95%9CTech
728x90