티스토리 뷰

 

Dalvik의 GC는 CMS 알고리즘을 사용하고, ART GC는 CMS 알고리즘을 개선한 Customed CMS 알고리즘을 사용한다. 

CMS 알고리즘은 이전 포스팅인 Garbage Collection 동작 방식에서 다룬 적 있기 때문에 이번 포스팅에서는 ART GC인 Customed CMS 알고리즘이 기존 CMS 알고리즘에서 어떻게 개선되었는지에 대해 정리해보려 한다.

 

이 글은 ART 가비지 컬렉션 디버깅하기를 참고해서 작성했다.

 


 

ART는 다음과 같이 GC 방법을 개선했다.

  • Dalvik은 STW 횟수가 2회(Initial Mart & Remark)이지만 ART CMS 가비지 컬렉션은 Remark에서만 1회 발생한다.

    • ART에서는 Initial Mark 단계에서 GC thread가 모든 루트 객체를 체크하는 것이 아니라 자신의 루트 객체만 살아있는지 체크(Marking)하고 즉시 다시 실행한다. 그렇기 때문에 STW가 발생하지 않고 Concurrent하게 수행된다.

  • ART GC는 Dalvik와 유사하게 Remark 단계에서 STW가 발생한다. 하지만 ART GC는 이 STW 중에 일부가 Concurrent하게 수행되기 때문에 인식할 수 있는 pause time이 두드러지게 줄어든다. Concurrent하게 수행되는 일부 작업으로는 Reference 처리, 시스템 객체의 weak 스위핑(ex. JNI weak global), thread가 아닌 루트를 Remark, card precleaning 등이 있다. 이 외에 정리가 필요한 카드를 스캐닝하고 thread 루트를 Remark하는 작업은 STW가 발생한다.

  • Static CMS Collector를 통해 GC 처리량을 늘렸다. Static CMS는 생성된 지 얼마 안 된 객체의 경우 전용 영역이 아니라 기본적으로 java.lang.Object의 배열인 할당 스택에 보관되는데, 이렇게 하면 STW를 낮은 수준으로 유지하는 데 필요한 객체를 이동시키지 않아도 된다. 하지만 객체 그래프가 복잡한 힙의 경우 컬렉션 시간이 길어진다는 단점이 있다.

  • ART는 최근에 할당 된 수명이 짧은 객체를 sweeping하는 특별한 경우에 총 GC 시간이 줄어든다.

  • Dalvik에서는 가비지 컬렉션 에르고노믹스(Ergonomics)를 개선하여 Concurrent GC를 더욱 적절한 때에 실행한다. 결과적으로 힙이 이미 가득 찼을 때 메모리를 할당하려고 시도하는 경우 앱을 중지 할 필요가 없다.

    • 에르고노믹스(Ergonomics)

      • Dalvik에서는 적절한 시기를 넘기고 Concurrent GC를 시작하는 경우 더 이상 할당을 위한 GC가 실행되지 않는다는 것이다. 이 경우 단점은 GC에서 차단하지 않는 경우 힙이 Dalvik보다 커질 수도 있다는 점이다. 여기서 ART에서는 힙 압축을 통해 프로세스가 백그라운드 프로세스 상태로 변경될 때 힙의 단편화를 압축하여 이 문제를 완화한다.

      • CMS GC 에르고노믹스에는 정기적으로 실행되는 GC의 두 가지 유형인 Static CMSPartial CMS가 있다. GC 에르고노믹스의 경우 Partial CMS보다 Static CMS를 더 많이 실행하는 것이 좋다. GC는 마지막 해제된 마지막 GC의 처리량( 해제된 바이트 수 / GC 지속 시간(초) )이 Partial CMS의 평균 처리량보다 작아질 때까지 Static CMS를 실행한다. 이 경우 에르고노믹스는 다음 Concurrent GC를 Static CMS가 아닌 Partial CMS로 계획한다. Partial CMS가 완료되면 에르고노믹스는 다음 GC를 다시 Static CMS로 변경한다. 에르고노믹스 작동의 핵심 요소 중 하나는 Static CMS가 완료 후에도 Static CMS에서 힙 공간 한도를 조정하지 않는다는 것이다. 이로 인해 Static CMS의 처리량이 Partial CMS 처리량보다 낮아질 때까지 Static CMS가 더 자주 발생하면서 힙이 증가하게 된다.

 

ART GC와 Dalvik의 또 다른 주요 차이점 중 하나는 ART GC에 moving GC(=compacting GC)를 도입했다는 것이다. OutOfMemory 에러는 앱의 메모리 부족으로 인한 것이 아니라 객체 할당을 위한 메모리 블록이 없을 때도 발생한다. 이러한 에러가 Android 오픈 소스 프로젝트 (AOSP)가 ART 용 압축 GC를 개발하는 이유이다. moving GC는 해제 된 단일 블록을 메모리의 한 위치에 병합하여 이러한 문제를 해결할 수 있다. 

 

Dalvik에서 사용한 CMS(Concurrent Mark Sweep) 알고리즘은 Heap Compaction 작업을 수행하지 않았기 때문에 힙 메모리 단편화가 발생하고, 연속적인 메모리 할당이 힘들 정도로 단편화가 심한 경우에 Compaction을 진행하였다. 이 Compaction 작업에서 앱이 멈추는 STW(=Stop The World) 상태가 오래 걸린다는 단점이 있었다.

그래서 ART에서는 Compacting GC를 도입했고, 이로써 메모리 파편화를 제거함으로써 메모리 공간의 효율성을 높이고, 좀 더 빠른 할당이 가능해지면서 OOM 같은 예외의 빈도도 줄일 수 있게 개선되었다. (앱이 백그라운드로 내려가면 ART가 Compacting 작업을 진행한다.)

 

더 자세하게 들어가면 moving GC를 도입한 이유는 힙 압축을 통해 백그라운드 앱의 메모리 사용량을 줄일 수 있기 때문이다. 현재 힙 압축을 발생시키는 이벤트는 ActivityManager 프로세스 상태 변경 트리거로, 앱이 백그라운드로 이동하면 앱은 프로세스 상태가 더 이상 ‘버벅거림을 인식할 수 없는 상태’라고 ART에 알린다. 이렇게 하면 ART에서 compaction 및 monitor deflation과 같이 긴 시간 동안 애플리케이션 스레드 일시중지를 발생시키는 작업을 수행할 수 있게 된다. 현재 사용되는 moving GC 2가지는 semi-space compaction과 homogeneous space compaction이다.

  • semi-space compaction

    • 객체는 2개의 긴밀하게 압축된 두 bump-pointer-space 사이를 이동한다. 이 moving GC는 homogeneous space compaction에 비해 메모리를 조금 더 절약하기 때문에 메모리 용량이 작은 기기에서 발생한다. 객체를 긴밀하게 압축하면 메모리를 추가로 절약할 수 있으며 이 경우 RosAlloc/DlMalloc 할당 오버헤드를 피할 수 있다. 그러나 앱이 포그라운드로 올라올 때 CMS가 bump-pointer-space에서 메모리 회수를 할 수 없기 때문에 또 다른 transition이 필요한데, 이 경우 STW가 눈에 띌 정도로 발생할 수 있기 때문에 바람직하지는 않다고 한다.

  • homogeneous space compaction

    • RosAlloc 공간 한쪽에서 다른 공간으로 복제하여 작동한다. 이렇게 하면 힙 파편화를 줄여 메모리 사용을 줄일 수 있다. 이 방식은 현재 메모리 용량이 작지 않은 기기에서 기본으로 적용되는 압축 모드이다. semi-space compaction에 비해 주된 이점은 앱이 포그라운드로 돌아갈 때 힙 전환이 필요하지 않다는 것이다.

 

 

Compaction GC를 도식화 한 그림

 

 

 

댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2025/02   »
1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28
글 보관함