-
Java Heap (with GC)Java/Basics 2020. 6. 8. 21:14
■Heap이란
- 인스턴스와 배열이 동적으로 생성되는 공간.
- 생성에 필요한 인스턴스와 배열의 메타 정보는 Heap 내의 Method Area에서 얻어온다.
- 모든 Thread가 공유하기 때문에 동기화 문제가 발생할 수 있다.
- Garbage Collection의 대상이 되는 영역.
- 개발자는 객체를 제거하기 위해 별도의 코드를 작성할 필요가 없고
오히려 부작용만 낳을 가능성이 큼. GC에 맡기는 것이 좋다
■Heap 구성
Heap의 각 영역이 의미하는 것은 아래 GC의 프로세스를 이해하면
더 구체적으로 알 수 있다.
Java 8 이전
Java 8 이전에는 Metaspace라고 지칭된 영역 대신에
PermGen(Permanat Generation Space) 라고 불리는 영역이 존재했었다.
이 영역은 클래스의 메타 정보와 GC에서 살아남은 객체들을
가지고 있는 공간이다.
생각해보면, Method Area와 역할이 동일해보인다.
사실 Method Area는 논리적으로(logicaly)
PermGen 안에 포함된다.
그리고 JVM을 실행할 때
-XX:PermSize : 초기 Perm size -XX:MaxPermSize : 최대 Perm size
이러한 옵션을 추가하면 PermGen의 사이즈를 설정할 수 있다.
(아마 Method Area의 크기도 특정한 비율로 같이 조절되지 않을까 싶다)
또한 Heap처럼 PermGen도 메모리 공간 오류가 발생할 수 있다.
- Exception in thread “main”: java.lang.OutOfMemoryError: Java heap spac
- Exception in thread “main”: java.lang.OutOfMemoryError: PermGen space
Java 8 이후
PermGen 영역이 사라졌다.
그리고 PermGen이 담당하던 역할을 다음과 같이 분리했다.
- 수정될 필요가 있는 데이터(static Object나 상수화된 String Object)
- 수정될 필요가 없는 데이터(class, method 등의 메타데이터)
수정될 필요가 있는 데이터는 Heap으로 옮겨 최대한 GC의 대상이
되도록 했고 수정될 필요가 없는 데이터는 OS가 Native Memory에서
직접 관리하도록 위임했다.
이 Memory Area를 Metaspace라고 부른다.
이 변화는 PermGen영역의 size 제한을 없애기 위한 것이 목적이다.
Metaspace가 Native memory에 위치함으로써 개발자는 영역 확보의 상한을
크게 의식할 필요가 없어지게 되었다.
■Garbage Collection (GC를 담당하는 프로세서도 GC라고 표현할 것이므로 문맥에 맞게 해석)
- Java 객체의 2가지 특징으로 인해 객체의 생명주기를 직접 관리해서
불필요한 객체를 메모리에서 해제시키도록 하는 개념(GC)이 등장하게 되었다.
첫번째 특징은 대부분의 객체는 금방 접근 불가능 상태(unreachable)가 되는 것이다.
두번째 특징은 오래된 객체에서 젊은 객체로의 참조는 아주 적게 존재한다는 것이다.
이 2가지 특징이 GC를 탄생시켰다.
- Heap의 인스턴스 중 Thead의 JVM stack에서 도달할 수 없는 것들(Unreachable)이
GC의 대상. 중요한건, 도달할 수 없는 것들을 pick 하는 것이 아니라 도달할 수 있는
것들을 pick한 후 나머지들을 메모리에서 제거한다.
이 방식을 Mark and Sweep 이라고 한다.
Mark
GC가 JVM stack의 모든 변수를 스캔하면서 각각이
힙 메모리의 어떤 인스턴스를 참조하고 있는지 찾음.
발견된 인스턴스 또한 어떤 인스턴스를 참조하고 있는지 찾음.
이 작업이 수행되면 모든 스레드는 중단되는데, 이를 'stop the world'라고 부름
(System.gc() 호출을 가볍게 보면 안될것)
Sweep
Mark되지 않은 인스턴스들을 제거
■Garbage Collection 실행 과정(with Heap Memory)
Young Generation
Eden
인스턴스들이 최초로 생성되는 공간.
이 영역이 가득차게 되면 Reachable 인스턴스들은 Survivor 0 으로 옮겨진다. 이를 MinorGC라고 한다.
반면 Unreachable 인스턴스들은 MinorGC가
실행될 때, 삭제된다.
Survivor 0
MinorGC가 한번 발생한 뒤 두번째 발생하게
되면 기존에 Survivor 0에 있었던 인스턴스 중
Reachable 인스턴스들은 Survivor 1로 옮겨지고
Unreachable 인스턴스들은 삭제된다.
옮겨질 때 각 인스턴스이 가지고 있는 고유의
age값이 증가한다.
Survivor 1
MinorGC가 세번 째 발생하게 되면
Survivor 1에 있었던 인스턴스들이 다시
Survivor 0 으로 옮겨지고 삭제된다.
이때도 각 age값이 증가한다.
인스턴스들이 Survivor 0 <-> Survivor 1 이동을
반복하고, 각 age값들이 특정 기준을 넘어서면
그 인스턴스들은 Old Generation으로 이동한다.
이를 Promotion 단계라고 한다.
Old Generation
Promotion 단계가 반복되면서 Old Generation이 가득 차게
되면 MajorGC가 발생하게 된다
https://yaboong.github.io/java/2018/06/09/java-garbage-collection/
https://mirinae312.github.io/develop/2018/06/04/jvm_gc.html
https://www.holaxprogramming.com/2013/07/20/java-jvm-gc/
https://skyoo2003.github.io/post/2016/10/25/introduction-to-java8
http://www.nextree.co.kr/p3878/
https://www.kdata.or.kr/info/info_04_view.html?field=&keyword=&type=techreport&page=18&dbnum=183834&mode=detail&type=techreport
https://johngrib.github.io/wiki/java8-why-permgen-removed/
'Java > Basics' 카테고리의 다른 글
Java Heap Dump (0) 2020.06.15 JVM, JRE, JDK (0) 2020.06.14 자바 컨벤션 모음 (0) 2020.05.21 자바 예외(Throwable) (0) 2020.05.20 메소드 vs 함수 (0) 2020.03.16 댓글