상세 컨텐츠

본문 제목

GC

안드로이드/basic

by 개발혱 2022. 6. 15. 21:28

본문

프로그램이 동적으로 할당했던 메모리 영역필요 없게 된 영역을 알아서 해제

                             Heap 영역                     어떤 변수도 가리키지 않음

 

GC가 왜 필요하지?

장점

  메모리 누수 방지, 해제된 메모리 접근 및 재해지 방지

단점

  GC 작업은 순수 오버헤드

  개발자가 언제 메모리 해제하는지 모름

 

GC 알고리즘

Reference Counting

  - 장점 : Heap 영역에 선언된 객체들이 reference count(해당 객체에 접근할 수 있는지)라는 별도 숫자를 가지고 있다고 생각하면 좋다. 해당 객체에 접근할 수 있는 방법이 하나도 없다면, 즉, reference count가 0에 다다르면 가비지 컬렉션 대상이 된다.

  - 단점 : 특정부분이 사용되지 않아 해제되었는데 해제된 쪽 다른 부분들이 서로가 서로를 참조하고 있다면 결국 사용하지 않는 메모리 영역은 해제되지 못하고 Memory Leak이 발생한다.

Mark And Sweep

Reference Counting의 순환 참조 문제를 해결할 수 있다. 루트에서부터 해당 객체에 접근 가능한지를 해제의 기준으로 삼는다. 루트부터 그래프 순회를 통해 연결된 객체들을 찾아내고 (Mark) 연결일 끊어진 객체들은 지우는 방식이다 (Sweep)

 단점

  - 의도적으로 GC를 실행시켜야 한다.

  - 어플리케이션 실행과 GC 실행이 병행된다. 



Root Space

- Stack의 로컬 변수

- Method Area의 Static 변수

- Native Method Stack의 JNI(Java Native Interface) 참조

Reachable

루트로부터 연결된 객체

Unreachable

루트로부터 연결되지 않은 객체

Compaction(오른쪽 정렬된 그림)

분산되어있던 메모리가 예쁘게 정리된 것이다.

메모리 파편화를 막는 Compaction이라고 한다.

 

Heap 영역

Young Generation (Minor GC)

출처 : https://www.youtube.com/watch?v=FMUpVA0Vvjw
출처 : https://www.youtube.com/watch?v=FMUpVA0Vvjw

1) Eden

새롭게 생성된 객체들이 할당되는 영역

MinorGC로부터 살아남은 객체들이 존재하는 영역

 

* Survival0, Survival1 둘 중 하나는 비어있어야 함.

jstat라는 툴을 통해 JVM 모니터링(출처 : https://www.youtube.com/watch?v=FMUpVA0Vvjw)

2) Survival0

Eden영역이 꽉차고 꽉 찬 영역들이 생기면 minor GC가 되면서 Eden 영역이 Mark And Sweep이 진행되고 루트로부터 Reachable이라 판단된 객체는 Survival0 영역으로 옮겨진다. Minor GC에서 살아남을 때마다 1씩 증가(Age-bit)라고 한다.

3) Survival1

Survival0이 꽉차면 Survival1로 옮겨진다. Age-bit가 3이 될 때 오랫동안 참조되는 객체라고 판단하고 Old Generation영역으로 이동된다.

 * Promotion : Young Generation에서 Old Generation으로 옮겨지는 과정

    Java8 경우, Palleral GC를 사용해서 age bit가 15가 되면 promotion이 진행된다.

 

Old Generation (Major GC / Full GC)

- Major GC는 Minor GC보다 GC 처리 시간이 더 오래 걸리게 된다. 

- 접근 불가능 상태로 되지 않아 Young 영역에 살아남은 객체가 여기로 복사된다.

 

* Stop The Wolrd

- GC를 실행하기 위해 JVM이 애플리케이션 실행을 멈추는 것

 

GC 방식

* 어플리케이션 사용성을 유지하면서 효율적으로 GC를 사용하는 것이 꽤나 어려운 작업이다.

Serial GC

- 하나의 쓰레드로 GC를 실행

- Stop The World 시간이 긺

- 싱글 쓰레드 환경 및 Heap이 매우 작을 때 사용

 

 

 

 

 

 

 

 

 

 

Parallel GC

- 여러 개의 스레드로 GC를 실행

- 멀티 코어 환경에서 사용(애플리케이션 처리속도 향상하기 위해서 사용)

- Java 8의 default GC방식

 

 

 

 

 

 

 

CMS(ConcMarkSweep) GC

- Stop The World 최소화를 위해 고안

- GC 작업을 어플리케이션과 동시에 실행하여 Stop The World를 최소화한다.

- 단점, 메모리와 CPU를 많이 사용하고, Mark-And-Sweep과정 이후 메모리 파편화를 해결하는 Compaction이 기본적으로 제공되지 않는다.

- G1 GC 등장에 따라 Deprecated

 

 

 

 

G1(Garbage First) GC

- Garbage First (G1)

- Heap을 Region으로 나누어 사용

  Heap을 일정 크기의 Region으로 잘게 나누어 어떤 영역은 Young Generation, 어떤 영역은 Old Generation으로 활용한다.

  영역별 Region 개수를 튜닝한다.

  Stop The World 최소화 가능

- Java 9부터 default GC 방식

 

JVM 튜닝

 객체 생성 자체를 줄이려는 코드 레벨에서의 개선이 선행되어야 한다.

 GC 튜닝의 목표

- Old Generation으로 넘어가는 객체 최소화 하기

- Major GC 시간을 짧게 유지하기(적게 유지하거나 빠른 시간 내에 끝내는 것이 목표)

  - Young Generation과 Old Generation을 각각 얼마만큼 할당하는 것이 적당한지를 판단해야 한다.

  - 메모리가 너무 크다면 GC는 가끔 일어나겠지만, 오래 걸릴 것이고 메모리가 너무 작다면 GC는 자주 일어나겠지만, 금방 끝날 것이다.

 GC 튜닝 과정

- GC 상태 모니터링하기

- 알맞은 GC 방식과 메모리 크기 설정

- 적용하기

 

Android GC 적용 사례

- 저사양 태블릿 사용 후 큰 이미지 리소스 많이 사용하게 되면서 화면 이동할 때마다 비트맵이 누적되고 일정 메모리 영역 초과하니 앱이 죽는 이슈 발생. 

  - 해결 사항 : 화면 전환 시, Bitmap 메모리를 recycle() 시켜준 후, null 값으로 초기화함.

 

Android Heap 영역 설계 고려

- 변수의 범위를 좁혀라. 클래스 멤버 변수를 사용하는 것보다 지역변수를 사용하는 편이 좋다.

 

참고 자료

- [10분 테코톡] 🤔 조엘의 GC

- Java Garbage Collection

- 읽기 좋은 코드가 좋은 코드다. p.138

관련글 더보기