Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Devfest Incheon / Songdo 2024 -안드로이드 내부에서 일어나는 ...

Dabin Moon
December 21, 2024

Devfest Incheon / Songdo 2024 -안드로이드 내부에서 일어나는 메모리 관리에 대해 알아보자(거기에 효율적 메모리 관리를 곁들인)

Devfest Incheon / Songdo 2024에서 발표한 안드로이드 내부에서 일어나는 메모리 관리에 대해 알아보자(거기에 효율적 메모리 관리를 곁들인) Speaker Deck입니다.

https://festa.io/events/6324

Dabin Moon

December 21, 2024
Tweet

More Decks by Dabin Moon

Other Decks in Programming

Transcript

  1. 인사이드 안드로이드 : 안드로이드 내부에서 일어나는 메모리 관리 구해줘! 메모리

    : 안드로이드의 메모리 부족 관리 기법 곁들임 : 개발자가 할 수 있는 효율적 메모리 관리 Index
  2. 안드로이드 내부에서 메모리 관리는.. 여러 AOSP 레이어가 서로 협력하며 메모리

    관리가 이루어진다 AOSP(Android Open Source Project) 아키텍처 kernel swap daemon(kswapd) Garbage Collection, Dalvik Heap zygote Low-memory killer(lmkd)
  3. 안드로이드 커널은 리눅스 커널 기반으로 이뤄져 있다 • 따라서 안드로이드의

    메모리 관리 기법은 리눅스 커널의 메모리 관리 기법과 비슷한 부분이 많다 • 모바일 디바이스 환경에서 사용되는 안드로이드 OS 특성상 리눅스 방식과 달라지는 부분도 존재한다
  4. 메모리 페이징 기법이란? 가상 메모리 공간을 고정된 크기의 블록으로 쪼개어

    메모리를 운용하는 기법 이 때 쪼개진 가상 메모리 블록의 단위를 Page라고 한다 물리 메모리 공간도 가상 메모리 페이지와 같은 크기의 블록으로 쪼개어 가상 메모리 페이지와 Mapping시킨다 가상 메모리 페이지와 물리 메모리 프레임의 Mapping 정보가 담긴 페이지 테이블을 통해 물리 메모리에 접근함 이 때 쪼개진 물리 메모리 블록의 단위를 Frame이라고 한다 메모리 불연속 할당(Non Contiguous Memory Allocation) 기법
  5. 메모리 페이징 기법이란? Frame8(4KB) Frame7(4KB) Frame6(4KB) Frame5(4KB) Frame4(4KB) Frame3(4KB) Frame2(4KB)

    Frame1(4KB) Frame0(4KB) Physical Memory (RAM) Virtual Memory Page3(4KB) Page2(4KB) Page1(4KB) Page0(4KB) Page4(4KB) Page3(4KB) Page2(4KB) Page1(4KB) Page0(4KB) Process2 Process1 - 8 6 7 4 Page Table2 Page Table1 - 3 2 1 0 9 5 2 1 0 4 3 2 1 0 Frame9(4KB)
  6. 메모리 연속 할당 VS 불연속 할당 메모리 연속 할당 (Contiguous

    Memory Allocation) 메모리 불연속 할당 (Non Contiguous Memory Allocation) 물리 메모리의 연속적인 공간을 프로세스에 할당하는 방식 연속되지 않은 물리 메모리의 여러 영역을 프로세스에 할당하는 방식 사진 출처 : https://www.scaler.com/topics/contiguous-and-non-contiguous-memory-allocation-in-os/ • Memory Paging(Android) • Memory Segmentation 대표적인 방식 • 고정 분할 기법(Fixed Partitioning) • 가변 분할 기법(Dynamic Partitioning) 대표적인 방식
  7. • 이를 해결하기 위해 memory compaction 발생 => 비용 메모리

    연속 할당 VS 불연속 할당 메모리 연속 할당 (Contiguous Memory Allocation) 메모리 불연속 할당 (Non Contiguous Memory Allocation) 사진 출처 : https://www.scaler.com/topics/contiguous-and-non-contiguous-memory-allocation-in-os/ 장점 물리적으로 인접해 있는 메모리 블록을 할당하기 때문에, 메모리 할당 및 접근이 불연속 할당에 비해 빠름 단점 인접한 메모리만 할당할 수 있기 때문에 외부 단편화(External Fragmentation) 가 발생할 가능성이 높다 • 메모리 페이징 방식의 경우 내부 단편화가 발생할 가능성이 존재 • 가상 주소 변환 과정이 필요하기 때문에 메모리 할당 및 접근이 연속 할당에 비해 느림 장점 • 물리적으로 연속되지 않아도 메모리 블록을 할당할 수 있기 때문에 외부 단편화로 인한 메모리 공간 낭비가 줄어든다 • 물리 메모리를 관리하는 부담은 커널에 위임하고, 프로세스에서는 추상화된 가상 메모리 영역만 바라보면 된다 단점 🌟안드로이드는 메모리 불연속 할당 기법의 장단점을 가짐
  8. 메모리 연속 할당 VS 불연속 할당 : External Fragmentation 연속

    할당 불연속 할당 비어있는 두 블럭을 합치면 들어갈 수 있을 것 같은데, 서로 떨어져 있네; 공간 좀 땡겨주세요 Physical Memory Process0 Process1 Process2 남아있는 총 메모리 공간이 프로세스가 요청한 메모리 공간보다 크지만, 남아있는 공간이 연속적이지 않아 메모리를 할당할 수 없는 현상 외부 단편화(External Fragmentation)
  9. 반면에 메모리 페이징 기법은 Internal Fragmentation이 발생할 위험이 있음 3KB

    빈 공간 프로세스가 필요한 메모리 공간보다 더 큰 메모리가 할당되어 메모리 공간 낭비가 발생하는 현상 내부 단편화(Internal Fragmentation) 4KB Ex ) 1KB
  10. 안드로이드에서의 메모리 페이징 • 안드로이드에서는 기본적으로 4KB 단위의 메모리 페이지

    사용 (New) Android15부터는 16KB 단위의 메모리 페이지 지원 • 시스템에 메모리 문제가 있는 동안 앱 실행 시간 단축: 평균 3.16% 감소, 테스트한 일부 앱의 경우 더 큰 개선 (최대 30%) • 앱 실행 중 전원 소모 감소: 평균 4.56% 감소 • 카메라 실행 속도 향상: 평균 핫 스타트 속도가 4.48%, 콜드 스타트 속도가 6.60% 빨라짐 • 시스템 부팅 시간 개선: 평균 8% (약 950밀리초) 개선됨 16KB 페이지 크기로 구성된 기기는 평균적으로 약간 더 많은 메모리를 사용하지만 시스템과 앱 성능이 개선됨 • 16KB 페이지 개발자 가이드 : https://developer.android.com/guide/practices/page-sizes?hl=ko#test • 16KB 페이지 AOSP 문서 : https://source.android.com/docs/core/architecture/16kb-page-size/16kb 내부 단편화(Internal Fragmentation) CPU 오버헤드 • 16KB 기기 테스트 ◦ 16KB 기반 Android 15 시스템 이미지 가상 머신 ◦ Android 15 QPR1 버전 이상 기기에서 제공되는 개발자 옵션(Boot With 16KB page size) 사용 ▪ 지원 기기 : Pixel 8, Pixel 8 Pro, Pixel 8a(Android 15 QPR1 이상)
  11. 스왑 공간(Swap Space)이란? 가상 메모리에서 물리 메모리(RAM)외에 가상 주소 공간으로

    사용할 수 있는 여유 공간을 의미 사진 출처 : https://ko.wikipedia.org/wiki/%EA%B0%80%EC%83%81_%EB%A9%94%EB%AA%A8%EB%A6%AC • 보통 하드 디스크의 일부를 이런 Swap Space로 사용 • 사용자가 물리 메모리 크기의 제약으로부터 자유로워질 수 있게 해줌 • 안드로이드는 (디스크)스왑 공간(Swap Space)을 제공하지 않는다 안드로이드에서의 메모리 페이징 (안드로이드 개발자가 OOM에 유의하며 개발해야하는 EU..)
  12. 핸디한 안드로이드 기기에 어울리지 않는다 Q. 안드로이드에서는 왜 디스크 스왑

    공간을 제공하지 않나요? A. 안드로이드에는 스왑 공간 역할을 할 하드디스크가 없다 이러한 이유로 안드로이드 기기에선 플래시 메모리만 비휘발성 메모리로 사용 안드로이드 기기에는 왜 하드 디스크가 없을까? 1. 배터리는 중요한 자원! 하드 디스크는 모터로 인해 전력을 어마무시하게 잡아먹기 때문에 배터리가 중요한 리소스인 안드로이드 기기에 어울리지 않는다 2. 모바일 기기는 망가지기 쉽다 하드 디스크는 물리적 충격으로 발생하는 배드 섹터에 취약하기 때문에, 물리적 충격에 쉽게 망가지는 안드로이드 기기에 어울리지 않는다 3. 하드 디스크는 플래시 메모리보다 크고 무겁다
  13. Q. 그렇다면 플래시 메모리를 스왑 공간으로 사용하면 되는 거 아닌가요?

    플래시 메모리를 스왑 공간으로 사용할 경우 안드로이드 저장소의 수명이 심각하게 단축될 수 있기 때문에 안드로이드에서는 디스크 스왑 공간을 따로 두지 않는다 그에 대한 보완책으로 안드로이드 4.4(Kitkat)버전부터 zRAM이라는 메모리 절약 커널을 통해 스왑 기능 지원 A. 플래시 메모리는 쓰기 작업으로 인한 수명 단축이 심하다
  14. 메모리 페이지 유형 Free Page(Unused Page) • 현재 RAM에서 사용

    가능한 Page Used Page • 현재 RAM에서 사용 중인 Page ◦ Cached Page : 저장소 파일 기반 페이지 ◦ Anonymous Page : 특정 파일과 매핑되지 않는 페이지
  15. Used Pages에 대해 좀 더 자세히 알아보자 • 저장소에 있는

    파일을 프로세스의 주소 공간으로 매핑하여, 데이터에 대한 빠른 접근과 수정을 가능하게 함 Private : 하나의 프로세스에서 소유하고 공유되지 않는 페이지 Shared : 여러 프로세스에서 사용되는 페이지 • 저장소의 특정 파일으로부터 매핑되지 않은, 커널로부터 할당된 메모리 페이지 Dirty Page Cached Page (== file backed-page) Anonymous Page 종류 메모리 맵 파일 기법 ◦ ex. MAP_ANONYMOUS 플래그가 설정된 mmap()에 의해 할당된 페이지 종류 용어사전 Clean Page Dirty Page • 저장소에 있는 파일의 수정되지 않은 복사본 ◦ kswapd로 삭제하여 Free Page를 늘릴 수 있음 • 애플리케이션 프로세스의 쓰기 작업 등으로 수정된 복사본 ◦ kswapd를 통해 zRAM으로 이동하거나 zRAM에서 압축하여 사용 가능한 메모리를 늘릴 수 있음 ◦ Clean Page ◦ Dirty Page ▪ msync()나 munmap()을 명시적으로 사용하여 사용 가능한 메모리를 늘릴 수 있음 ◦ Clean Page ◦ Dirty Page
  16. kswapd가 클린 페이지를 삭제할 수 있는 이유 Disk 원본 데이터

    클린 페이지는 저장소에 있는 파일(또는 파일의 일부)의 수정되지 않은 정확한 복사이기 때문 • 클린 페이지는 저장소의 데이터를 사용하여 삭제되더라도 같은 데이터를 다시 생성할 수 있음 ⚠ 더티 페이지는 더 이상 파일의 정확한 복사본을 포함하지 않음 반면에.. • 더티 페이지는 삭제하면 데이터가 손실되기 때문에 삭제할 수 없음 ◦ 저장소 파일 기반이 아닌 Anonymous Page의 경우 저장소로부터 데이터를 복원할 수 없기 때문에 더티 페이지만 존재 equals not equals 누구세요..? Clean Page Dirty Page Anonymous Page
  17. 메모리 매핑 기법(메모리 맵 파일, Memory-mapped file)이란? 사진 출처 :

    https://www.geeksforgeeks.org/memory-mapped-files-in-os/ • 캐시 페이지(Cached Page) • .so mmap • .dex mmap • .oat mmap 프로세스의 가상 메모리 주소 공간에 저장소의 파일을 매핑한 뒤 가상 메모리 주소에 접근하는 것으로 파일의 읽기/쓰기를 대신하는 기법 장점 안드로이드의 메모리 맵 파일 전통적인 파일 입출력 API 보다 속도가 빠르다 But 페이지 부재(Page Fault)시 데이터 전송 시간이 오버헤드로 작용 파일에 접근할 때 지연 적재(Lazy Loading)를 사용 파일의 크기가 매우 크더라도 필요한 부분만 파일에서 불러와 작업할 수 있음 • .art mmap • .jar mmap • .apk mmap • .ttf mmap … 등등
  18. 안드로이드 메모리 유형 • RAM(메인 메모리) ◦ 가장 빠른 메모리

    유형 ◦ 휘발성 메모리 ◦ 제한된 용량 사진 출처 : https://developer.android.com/topic/performance/memory-management?hl=ko • 저장소(디스크, 보조기억장치) ◦ 비휘발성 메모리 ◦ RAM보다 용량이 훨씬 큼 ◦ 스왑 공간에 사용되지 않음 ◦ eMMC, UFS 등과 같은 플래시 메모리
  19. 안드로이드 메모리 유형 사진 출처 : https://developer.android.com/topic/performance/memory-management?hl=ko • zRAM(스왑 공간)

    ◦ 안드로이드 4.4(Kitkat)부터 추가된 스왑 공간 ◦ RAM 영역의 일부 ◦ 모든 페이지는 zRAM에 배치될 때 압축되고 zRAM에서 나갈 때 압축 해제됨 ◦ 기기 제조업체(OEM)가 zRAM의 최대 크기를 설정할 수 있음 ▪ Samsung - RAM Plus ◦ RAM의 일부를 쓰는 것이기 때문에 zRAM의 용량은 RAM 용량을 넘어갈 수 없음 ◦ Deflate, LZ4 혹은 LZO, zstd 같은 고속 압축 알고리즘을 사용해서 페이지 압축
  20. 들어가기 전에.. 제한적인 스왑공간으로 인해 더욱 여유 메모리가 부족 안드로이드는

    여유 메모리가 부족할 때가 많다 Android 플랫폼은 사용 가능한 메모리가 있다는 것은 메모리 낭비라는 전제 하에 실행된다 “ ex. 시스템은 앱이 닫힌 후에도 앱을 메모리에 캐싱 사용자가 닫힌 앱을 다시 열었을 때 빠르게 앱을 실행할 수 있게하기 위해 + ∴ 각 애플리케이션 프로세스 힙 크기를 제한
  21. 앱 프로세스당 힙 크기 제한 java.lang.OutOfMemoryError 3개씩 가져가세요^^ 가져가세요 ^^

    기능적인 멀티태스킹 환경을 유지하기 위해 안드로이드는 각 애플리케이션 프로세스 힙 크기에 제한을 설정함 • 정확한 힙 크기 제한은 기기마다 다름 => 보통 OEM에서 기기 RAM 크기에 따라 적당한 값을 설정 • 앱이 힙 용량에 도달한 상태에서 더 많은 메모리를 할당하려고 하면 OutOfMemoryError 발생 OEM : 기기 제조업체
  22. 앱 프로세스당 힙 크기 제한 java.lang.OutOfMemoryError 3개씩 가져가세요^^ 가져가세요 ^^

    기능적인 멀티태스킹 환경을 유지하기 위해 안드로이드는 각 애플리케이션 프로세스 힙 크기에 제한을 설정함 • 정확한 힙 크기 제한은 기기마다 다름 => 보통 OEM에서 기기 RAM 크기에 따라 적당한 값을 설정 • 앱이 힙 용량에 도달한 상태에서 더 많은 메모리를 할당하려고 하면 OutOfMemoryError 발생 OEM : 기기 제조업체 이러한 이유들로 인해 안드로이드에서 메모리 부족 관리는 매우 중요!!
  23. 안드로이드의 메모리 부족 관리 기법 1. 메모리 공유 2. 커널

    스왑 데몬(kswapd) 3. 로우 메모리 킬러(lmkd) 4. 가비지 컬렉션
  24. 메모리 공유 - Zygote Zygote 동일한 애플리케이션 바이너리 인터페이스 (ABI)를

    사용하는 모든 시스템 및 앱 프로세스의 루트 역할을 하는 Android 운영체제의 프로세스 사진 출처 : [책] 인사이드 안드로이드 1. 리눅스의 init 2. 리눅스의 init에서 Zygote Process 실행 3. 새로운 Application Process를 실행하려 할 때, Zygote Process fork 4. fork된 Zygote Process 위에서 Application 구동 1. ART VM 또는 달빅(Dalvik) VM의 초기화 수행 2. 안드로이드 Class와 Resource 사전 로딩(Pre loading) Zygote 호출부 코드 : https://android.googlesource.com/platform/frameworks/base/+/master/cmds/app_process/app_main.cpp ZygoteInit 코드 : https://android.googlesource.com/platform/frameworks/base.git/+/master/core/java/com/android/internal/os/ZygoteInit.java Zygote는 안드로이드에서 가장 먼저 만들어 지는 Process 메모리 관리에 있어 Zygote의 역할 하나의 Application이 실행되기 까지.. 모든 애플리케이션이 실행될 때 Zygote를 fork해서 실행되기 때문에 Zygote는 모든 애플리케이션 프로세스의 부모라고 볼 수 있다
  25. 메모리 공유 - Zygote의 이점 1. 애플리케이션 시작 시간 감축

    or ART VM 사진 출처 : [책] 인사이드 안드로이드 애플리케이션이 실행될 때마다 자신이 동작할 가상 머신을 초기화한다면? 애플리케이션 시작 과정에 많은 시간이 소요 모든 애플리케이션 프로세스는 Zygote 프로세스를 fork한다 Zygote 프로세스에 초기화된 가상 머신(ART, Dalvik)코드 및 Pre loading된 메모리 정보를 복사하여 사용함으로써 애플리케이션이 시작되는 시간을 단축
  26. 메모리 공유 - Zygote의 이점 • 여러 프로세스에서 동일한 page

    table을 사용하여 동일한 데이터를 공유하는 방식 • 쓰기 작업 발생시 원본 메모리 페이지를 복사한 페이지를 수정하는 방식으로 작동 모든 자식 애플리케이션 프로세스는 Zygote 프로세스의 페이지 테이블을 복사 2. 메모리 공유 최적화 or ART VM 사진 출처 : [책] 인사이드 안드로이드 COW 방식 (copy-on-write) (== 모든 자식 애플리케이션 프로세스가 Zygote의 메모리 영역을 공유함) COW(copy-on-write)란? 변경 사항이 발생하지 않으면 개인 프로세스에 복사본이 생성되지 않아 메모리 리소스가 절약됨
  27. 커널 스왑 데몬(kswapd) 사진 출처 : https://www.youtube.com/watch?v=w7K0jio8afM Linux 커널의 일부로,

    Used Page를 Free Page로 회수하는 데몬 커널 스왑 데몬 코드 : https://android.googlesource.com/kernel/common/+/refs/heads/android-mainline/mm/vmscan.c • Free Memory가 kswapd 임계값 이하로 떨어질 때 작동하기 시작 • kswapd 임계값 이상에 도달하면 kswapd가 메모리 회수를 중단함 But! 너무 많은 Cached Page가 회수되면 페이지 부재(Page Fault)로 페이지를 리로드하는 데 시간이 걸리게 됨
  28. 커널 스왑 데몬(kswapd) - Clean Page의 경우 동일한 데이터가 저장소에도

    존재 사진 출처 : https://developer.android.com/topic/performance/memory-management?hl=ko Clean Page의 경우 저장소에 있는 파일의 수정되지 않은 복사본이므로... • kswapd는 클린 페이지를 삭제하여 메모리 회수 • kswapd의 메모리 회수로 클린 페이지의 페이지 폴트가 발생하면 시스템은 저장소로부터 클린 페이지를 RAM으로 복사함 demand paging : Page 요청이 들어오면 디스크로부터 페이지를 RAM으로 할당하는 방식
  29. 커널 스왑 데몬(kswapd) - Dirty Page의 경우 사진 출처 :

    https://developer.android.com/topic/performance/memory-management?hl=ko Dirty Page의 경우 애플리케이션 프로세스의 쓰기 작업 등으로 수정된 복사본이므로... • 더티 페이지는 삭제되면 데이터가 손실되기 때문에 스왑 공간인 zRAM으로 이동시켜 페이지를 압축하여 메모리 회수 • 프로세스가 zRAM의 더티 페이지를 사용하려고 하면 페이지가 압축 해제되고 다시 RAM으로 이동 • 압축된 더티 페이지와 매핑된 애플리케이션 프로세스가 종료되면 더티 페이지가 zRAM에서 삭제
  30. 로우 메모리 킬러(lmkd) 로우 메모리 킬러 코드 : https://android.googlesource.com/platform/system/memory/lmkd/+/refs/heads/main/lmkd.cpp 실행

    중인 Android 시스템의 메모리 상태를 모니터링하고, 시스템 성능을 만족할 만한 수준으로 유지하기 위해 필요성이 가장 낮은 프로세스를 종료하여 메모리를 확보하는 시스템 프로세스 • Kswapd로는 시스템에 충분한 메모리를 확보할 수 없는 경우가 많음 • 로우 메모리 킬러는 필요성이 가장 낮은 프로세스를 종료시켜 해당 프로세스가 사용하는 모든 메모리를 회수함 kswapd에 비해 메모리 회수량 • 가용 메모리가 로우 메모리 킬러의 임계값 이하로 떨어질 때 작동하기 시작 ◦ oom_adj_score라는 메모리 부족 점수를 사용하여 실행 중인 프로세스의 우선순위를 정하고, 최고 점수를 얻은 프로세스를 먼저 종료시킴 사진 출처 : https://www.youtube.com/watch?v=w7K0jio8afM
  31. 로우 메모리 킬러(lmkd)의 임계값 로우 메모리 킬러 임계값이 저장되는 위치

    minfree : 가용 메모리 페이지 임계값 adj : oom_adj_score(메모리 부족 점수) DeviceExplorer minfree와 adj 파일에 기록된 필드 값들은 각각 순서대로 짝을 이룬다 ex. ⚠기기마다 minfree, adj 값은 달라짐 현재 남은 page의 개수가 55296개 이하가 됐을때 oom_adj_score가 900 이상인 프로세스의 메모리를 회수한다
  32. 로우 메모리 킬러(lmkd) VS OOMK(Out-Of-Memory Killer) 메모리 부족 상황에서 OOM

    Score를 기준으로 프로세스의 우선순위를 정하고 점수가 높은 Process를 종료시켜 메모리를 확보하는 linux kernel 기능 OOMK(Out-Of-Memory Killer) oomk lmkd VS • OOMK의 기능을 안드로이드 환경에 맞게 확장한 것 • LMK는 리눅스 커널 4.12부터 커널 영역에서 삭제되고 사용자 공간으로 이동됨 • OOMK의 OOM Score 정책을 따르면 가상 메모리가 많이 할당된 주요 프로세스를 죽일 수 있기 때문에, oom_adj_score라는 새로운 점수 정책을 따름 • 리눅스 커널 영역에 존재 • 가용 공간 확보 효율을 높이기 위해 보통 가상 메모리를 가장 많이 할당한 프로세스에 높은 OOM Score를 부여하고 종료시킴 현재 포그라운드에서 사용 중인 앱 백그라운드로 내려간 앱 used memory lmkd : 백그라운드로 내려간 앱을 종료 oomk : 현재 포그라운드에서 사용 중인 앱을 종료 ex. 메모리 부족 상황에서..
  33. 로우 메모리 킬러(lmkd) - oom_adj_score (메모리 부족 점수) 1. 백그라운드

    앱 ◦ 현재는 활성화 되지 않고 백그라운드로 내려간 앱 ◦ oom_adj_score가 가장 높음 2. 바로 이전에 실행한 앱 ◦ 가장 최근에 사용한 백그라운드 앱 ◦ 백그라운드 앱보다 이전 앱으로 전환할 가능성이 높기 때문에 백그라운드 앱보다 우선순위가 높음 3. 홈 앱 ◦ 런처 앱 ◦ 이 앱을 종료하면 배경화면이 사라짐 4. 서비스 ◦ 싱킹이나 업로드 다운로드 등을 하기 위해 애플리케이션에서 시작한 서비스 5. 인식할 수 있는 앱 ◦ 사용자가 인식할 수 있는 포그라운드에 없는 앱(ex. 작은 UI를 표시하는 검색 프로세스, 음악 듣기) 6. 포그라운드 앱 ◦ 현재 사용 중인 앱 ◦ 종료하면 애플리케이션이 비정상 종료되는 것처럼 보여서 사용자가 기기에 문제가 있다고 생각할 수 있음 7. 영구(서비스) ◦ 전화, Wi-Fi와 같은 기기의 핵심 서비스 8. 시스템 ◦ 시스템 프로세스 ◦ 이러한 프로세스가 종료되면 휴대전화가 재부팅된 것처럼 보일 수 있음 9. 네이티브 ◦ 시스템에서 사용하는 매우 낮은 수준의 프로세스(ex. kswapd, init) 출처 : https://developer.android.com/topic/performance/memory-management?hl=ko ⚠기기마다 로우 메모리 킬러의 동작은 변경될 수 있음 표의 상단으로 갈 수록 oom_adj_score가 높아짐 최고 점수를 얻은 프로세스부터 종료시킴
  34. 로우 메모리 킬러(lmkd) TMI Android 9(Pie) 이상부터 LMK가 커널 영역에서

    빠져서 사용자 공간으로 이동함(lmkd) 커널 내 LMK 드라이버의 단점 • 대규모 파일 지원 활성 페이지 캐시가 포함된 워크로드에서 성능 저하로 인한 스래싱 발생 • LMK 커널 드라이버는 메모리 압력에 따라 확장하지 않고 여유 메모리 제한에 의존적 • 확장성이 떨어짐 • LMK 드라이버는 Slab Shrinker API와 연결 => 부담이 큰 작업용으로 설계되지 않아서 vmscan(kswapd) 프로세스 속도가 느려짐 • 리눅스 커널에 존재하는 vmpressure 이벤트 활용 Android 10 이상에서는 커널 압력 스톨 정보(PSI, Pressure Stall Information) 모니터를 사용하여 메모리 압력을 감지하는 새로운 lmkd 모드 지원(Android 9 백포팅) • vmpressure 신호의 단점 개선 ◦ 메모리 압력 감지가 더 정확해지고 불필요한 lmkd wakeup과 추가 컴퓨팅 리소스 사용이 발생을 줄임 Android 11 이상에서는 새로운 프로세스 종료 전략 도입 lmkd는 언제나 발전중 😊 • 고성능 기기와 저성능 기기(Android Go)에 모두 사용 가능
  35. 가비지 컬렉션 향후에 액세스할 수 없는 프로그램의 데이터 객체를 찾고

    해당 객체에서 사용한 리소스를 자동으로 찾아내어 회수하는 작업 Mark & Sweep STW(stop-the-world) • Mark : GC Root에서 시작해 이 Root가 참조하는 모든 오브젝트와, 그 오브젝트들이 참조하는 다른 오브젝트들을 탐색해 내려가며 Mark하는 단계 • Sweep : 가비지 컬렉터가 힙 내부를 돌면서 Mark되지 않은 메모리들을 해제(Reclaim)하는 단계 • GC를 실행하기 위해 JVM이 애플리케이션의 실행을 멈추는 것 • STW가 발생하면 GC를 실행하는 쓰레드를 제외한 나머지 스레드는 작업을 모두 멈춤 • 모든 가비지 컬렉션 알고리즘에서 발생함 • 대개 GC 튜닝이란 STW 시간을 줄이는 것을 의미 (성능 저하의 주범) 가비지 컬렉션 후 VM(Dalvik 또는 ART)은 힙을 탐색하며 사용하지 않는 메모리 페이지를 찾고 커널에 반환함
  36. 발전하는 가비지 컬렉션 GC는 앱 성능 저하 문제를 유발할 수

    있기 때문에, Android에서는 다양한 방법으로 GC 성능을 개선해 왔다 주목할만한 변화 과정 HoneyComb (Android 3.x) Kitkat, Lollipop (Android 4.4 ~ Android 5.x) Android Oreo (Android 8.0) Dalvik VM (~ Android4.4) ART VM (Android 4.4 ~ ) CMS 알고리즘 도입 (Concurrent Mark Sweep) Customed CMS 알고리즘 도입 • Foreground Compaction • STW 횟수 2회에서 1회로 줄임 CC GC 도입 (concurrent compacting) • Concurrent Compaction
  37. 발전하는 가비지 컬렉션 GC는 앱 성능 저하 문제를 유발할 수

    있기 때문에, Android에서는 다양한 방법으로 GC 성능을 개선해 왔다 사진 출처 : https://www.oracle.com/webfolder/technetwork/tutorials/obe/java/gc01/index.html Quince Tart (Android 10) Tiramisu (Android 13) 주목할만한 변화 과정 Generational Garbage Collection 도입 userfaultfd 기반 GC
  38. 안드로이드의 메모리 풋 프린트 계산 측정항목은 공유 페이지를 어떻게 계산하냐에

    따라 나뉘어짐 공유 페이지 애플리케이션의 메모리 공간을 확인할 때는 다음 측정 항목들 중 하나를 사용하면 된다 사진 출처 : https://developer.android.com/topic/performance/memory-management?hl=ko • Resident Set Size(RSS) ◦ 앱에서 사용하는 공유, 비공유 페이지 수 모두를 계산한 Size ◦ 메모리 할당의 변경사항을 추적하는 데 좋음 • Proportional Set Size(PSS) ◦ 앱에서 사용하는 비공유 페이지 수 + (앱에서 사용하는 공유 페이지 수 / 공유 페이지를 사용하는 프로세스 수) ▪ ex. 3개의 프로세스가 3MB 크기의 공유 페이지들을 공유하는 경우 각 프로세스는 PSS에서 1MB를 받음 ◦ 모든 프로세스에서 사용하는 메모리 양을 파악하려는 운영체제에 유용 • Unique Set Size(USS) ◦ 앱에서 사용하는 비공유 페이지 수만 계산한 Size (공유 페이지 수는 포함되지 않음)
  39. HoneyComb 이전의 비트맵 메모리 관리 dalvik heap 에서 java 비트맵

    참조가 끊어져서 gc가 되어도 네이티브 비트맵 메모리는 같은 시점에 gc 되지 않는 문제 존재 시대의 흐름에 따라 안드로이드 메모리 관리 기법은 항상 변화한다 Latte Story..☕ (나때는 말이야..) Dalvik VM에서의 메모리 부족 현상 JIT Compile 방식 => 실행 직전에 실행 부분 전체를 RAM에다 올리는 과정으로 인해 RAM 부족 현상 발생 😇무수한 OOM이...
  40. 들어가기 전에.. 엄청난 메모리 부족 나 lmkd, kswapd 개 쩌는

    모바일 하드웨어 가비지 컬렉션 Q. 요즘 기기 스펙도 좋고, 안드로이드 내부에서도 메모리 관리를 잘 해주는 것 같은데 꼭 개발자가 신경을 써야되는 것인가요?
  41. 개발자가 메모리 관리를 열심히 해야하는 EU.. 거시적인 이유 Android ecosystem을

    위해 사진 출처 : https://www.youtube.com/watch?v=w7K0jio8afM 애플리케이션 메모리 사용량과 요구사항이 증가하면 OEM에서 보급형 기기를 생산하지않게 될 수 있음 안드로이드 생태계의 많은 사용자를 배제하게됨
  42. 개발자가 메모리 관리를 열심히 해야하는 EU.. Android Go 스펙 우리

    앱의 유저 이탈을 막기 위해 ㅎㅎ 사진 출처 : https://www.youtube.com/watch?v=w7K0jio8afM 미시적인 이유 Android(Go edition) : RAM이 적은 보급형 스마트폰을 위해 제작된 모바일 운영 체제 2017년에 처음 안드로이드 Go 에디션을 발표했을때, 보급형 휴대전화를 사용하는 사람들이 전 세계 안드로이드 기기 출하량의 57%를 차지 “
  43. 효율적 메모리 관리 - 코드편 android:largeHeap = true 안드로이드는 각

    애플리케이션 프로세스 힙 크기에 제한을 설정하고, 해당 프로세스의 힙 크기가 제한을 넘어가면 OOM을 발생시킨다 AndroidManifest.xml android:largeHeap=true로 설정하면.. 보통 2배에서 4배까지 dalvik heap의 최대 크기가 늘어남 애플리케이션이 일반적으로 할당받는 Dalvik 힙보다 더 큰 사이즈의 힙을 할당 받는다 ⚠OEM에서 값을 어떻게 설정해놓냐에 따라 기기별로 largeHeap 사이즈는 달라질 수 있다
  44. 효율적 메모리 관리 - 코드편 onTrimMemory(int level) 메모리 상태를 체크하여

    시스템에서 불필요한 메모리 정리가 필요하다고 판단할 때 호출되는 콜백 • level : 애플리케이션이 수행해야할 메모리 정리 양에 대한 hint(ComponentCallbacks2에 정의된 상수 값) ◦ API level 35부터 많은 상수 값이 Deprecated 되어 아래 두 값만 수신할 수 있다 ▪ TRIM_MEMORY_BACKGROUND(Process가 LRU 리스트로 이동되었을 때) ▪ TRIM_MEMORY_UI_HIDDEN(Process가 더 이상 UI를 표시하지 않을 때) ex.
  45. 효율적 메모리 관리 - 코드편 Weak Reference, Soft Reference •

    Strong Reference - 일반적으로 변수를 선언하면 강한 참조 ◦ Strongly Reachable • Soft Reference ◦ softly Reachable ◦ 연결된 오브젝트에 strong 참조가 없다면 GC 발생시, 메모리가 여유로울 때는 객체를 그대로 유지하고 그렇지 않을 때는 메모리를 해제함 • Weak Reference ◦ Weak Reachable ◦ 연결된 오브젝트에 strong, soft 참조가 없다면 GC 발생시 메모리 해제
  46. 효율적 메모리 관리 - 도구편 dumpsys Android 기기에서 실행되는 도구로,

    시스템 서비스에 관한 정보를 제공 meminfo procstats 앱이 백그라운드에서 얼마나 오래 실행되는지, 그 시간 동안 얼마나 많은 메모리를 사용하는지 등 시간이 지남에 따라 앱이 어떻게 동작하는지 확인 ex. 3시간 동안의 애플리케이션 메모리 사용량 통계 특정 앱 프로세스의 메모리 사용 정보 스냅샷 adb shell dumpsys meminfo package_name|pid [-d]
  47. 효율적 메모리 관리 - 도구편 Android Profiler (Heap Dump, Java/Kotlin

    Allocations, Native Allocations) Perfetto https://perfetto.dev/docs/case-studies/memory 메모리 디버깅 툴 https://developer.android.com/studio/profile/mem ory-profiler?hl=ko
  48. 효율적 메모리 관리 - 도구편 Android Vitals - 실제 프로덕션

    앱에서 발생하는 이슈 파악 https://developer.android.com/topic/performance/vitals?hl=ko 느린 렌더링이나 정지된 프레임 등의 악성 동작을 식별하여 수정 Google Play 앱의 기술 품질을 개선하기 위한 툴 • 사용자가 앱을 실행하면 Android 기기는 안정성 측정항목, 성능 측정항목, 배터리 사용량, 권한 거부 등 품질 측면에 관한 정보를 기록 Android vitals 대시보드
  49. 효율적 메모리 관리 - 도구편 LeakCanary • application에 Memory Leak이

    존재하는지 Detection 해주는 Square의 라이브러리 stressapptest • 현실적인 고부하 상황을 만들어 앱의 다양한 메모리 및 하드웨어 제한사항을 테스트할 수 있는 메모리 인터페이스 테스트
  50. 효율적 메모리 관리 - 마음가짐(?)편 이건 여러분 모두가 다 잘

    하고 계실거라 생각합니다..^__^(아님 말고) 앱 크기를 줄이자 - 메모리에 로드되는 데이터의 크기도 줄어듦 ex. 이미지 용량 줄이기(png to webp), minifyEnabled & shrinkResources 등 메모리 누수 일으키는 케이스 유의 ex. Fragment Binding 메모리 해제, ViewModel에서 View 객체 참조 등
  51. 감사합니다! Android In Korea 안드로이드 내부에서 일어나는 메모리 관리에 대해

    알아보자 (거기에 효율적 메모리 관리를 곁들인) 문다빈