본문 바로가기
Android/Android 지식

Android의 효과적인 메모리 관리

by 쎄오SseO 2023. 11. 13.

안드로이드의 메모리 관리 방법에 대해 설명하려 합니다.

잘못된 부분이나 이해가지 않는 부분이 있다면 댓글 꼭 달아주세요!

 

 

안드로이드는 페이징 기법을 사용합니다.

페이징에 대해서는 설명이 잘 되어있는 글이 많기 때문에 페이징에 대한 설명은 넘어가겠습니다.

 

안드로이드는 사용 가능한 메모리가 있다면 메모리를 낭비하고 있다고 보고 사용 가능한 메모리를 최대한 사용하려고 합니다.

 

앱이 닫힌 후에도 앱을 메모리에 보관하여 사용자가 앱으로 빠르게 다시 전환할 수 있게 하는 등 사용 가능한 메모리를 최대한 사용하기 때문에 메모리 관리를 알고 올바르게 사용하는 것이 중요합니다.

 

 

zRAM

 

https://developer.android.com/static/images/games/memory-types.svg?hl=ko

 

Android는 zRAM을 활용합니다.

 

 

zRAM 이란?

 

RAM의 파티션(램의 일부분)으로 스왑 공간으로 사용됩니다.

 

페이지를 zRAM에 압축하여 배치하고, zRAM에서 RAM으로 복사될 때 압축이 해제됩니다.

 

메모리 영역 내에서 스왑하기 때문에 디스크에 엑세스하는 것보다 빠릅니다.

 

 

 

zRAM을 사용하는 이유?

 

1. 안드로이드에서는 저장소가 다른 Linux 구현에서처럼 스왑 공간에 사용되지 않기 때문

저장소에는 파일 시스템, 그리고 모든 앱 및 라이브러리 등과 같은 영구 데이터가 모두 포함됩니다. 빈번한 쓰기 작업으로 메모리에 마모가 발생하고 저장소의 수명을 단축시키기 때문입니다. 그렇기 때문에 zRAM을 스왑 공간으로 활용합니다.

 

2. 메모리 효율성 때문

zRAM은 RAM의 파티션인데 RAM으로 전부 활용하는 게 더 낫지 않을까? 라는 생각을 해보았습니다. 안드로이드에서 저장소를 다른 Linux 구현에서처럼 스왑 공간으로 사용하지 않은 이유도 있지만, 메모리 사용을 더 효과적으로 하기 위해서 인 걸 알 수 있었습니다.

 

압축해서 zRAM에 배치시키기 때문에 더 많은 메모리를 올릴 수 있다는 점과 디스크의 스왑 공간보다 더 빠른 반응 때문에 효과적으로 메모리를 사용할 수 있습니다.

 

 

kswapd (커널 스왑 데몬)

 

kswapd는 Linux 커널의 일부로, 사용 중인 메모리가 많다면 메모리를 회수하여 사용 가능한 메모리로 변환합니다.

 

Linux 커널은 사용 가능한 메모리의 threshold를 지정합니다. 낮은 threshold와 높은 threshold가 있는데, 사용 가능한 메모리가 낮은 threshold 아래로 떨어지면 kswapd가 메모리를 회수합니다. 높은 임계값에 도달하면 kswapd가 메모리 회수를 중지합니다.

 

kswapd가 메모리를 회수할 때 클린 페이지(메모리에서 수정되지 않은 데이터)는 삭제하여 회수할 수 있습니다. 더티 페이지(메모리에서 수정된 데이터)는 zRAM으로 압축하여 이동할 수 있습니다.

 

 

Threshold를 이용하는 이유

메모리에 페이지 부재율이 높다면 심각한 성능 저하를 초래합니다. 메모리를 적절히 사용하고 쓰레싱이 발생하지 않도록 Threshold를 초과하지 않도록 합니다.

 

Thrashing(쓰레싱)

Thrashing(쓰레싱)-메모리 영역에 접근하게 될 때, 메모리에 페이지 부재(=페이지 폴트(Page fault)율이 높은 것을 의미하며, 심각한 성능 저하를 초래합니다.- 활발하게 사용되는 페이지 집합을 지원해 줄 만큼 프레임이 충분히 할당 받지 못한 프로세스는 페이지 폴트(Page fault)가 발생하게 됩니다.이 때, 페이지 교체가 필요하지만 이미 활발히 사용되는 페이지들만으로 이루어져 있으므로 어떤 페이지가 교체되던 바로 다시 페이지 교체가 필요하게 될 것입니다.결과적으로 바로바로 반복해서 페이지 폴트가 발생하며, 교체된 페이지는 또 다시 얼마 지나지 않아 읽어올 필요가 생기게 됩니다. 이렇게 과도한 페이징 작업을 Thrasing(쓰레싱) 이라 합니다.

 

 

 

 

 

Low Memory Killer

 

kswapd로는 시스템에 충분한 메모리를 확보할 수 없는 경우가 많습니다. 이 경우 시스템은 onTrimMemory()를 사용하여 메모리가 부족하고 할당량을 줄여야 한다고 앱에 알립니다. 이 방법으로 충분하지 않으면 커널이 메모리를 확보하려고 프로세스를 종료하기 시작합니다. 이 작업을 실행하기 위해 로우 메모리 킬러(low-memory killer, LMK)를 사용합니다.

 

 

사용자의 프로세스 중에서 어떤 앱을 종료 시킬 것인지 판단하기 위해 ‘메모리 부족’ 점수를 사용하여 우선 순위를 정합니다. 위 사진은 메모리 점수가 높은 것부터 낮은 순서로 나열되어 있습니다. Native 항목이 가장 점수가 낮고, Background Apps가 점수가 가장 높습니다. 높은 점수부터 앱을 종료시킵니다.

 

 

 

Shared Pages, COW(Copy-On-Write)

 

Android에서는 공유 라이브러리 등 여러 프로세스 간에 메모리를 공유하면서 메모리를 효과적으로 사용합니다. 그리고 필요한 경우 COW를 사용합니다.

 

운영체제 공부를 하면서 재밌었던 것이 COW인데요. 안드로이드에서는 Zygote에서 사용되는 것을 알 수 있었습니다.

 

 

Copy-On-Write (COW)

여러 프로세스가 동일한 페이지를 사용한다면 프로세스가 각 페이지를 독립적으로 가지고 있을 필요 없이 페이지를 공유하게 하고, 그 페이지를 수정하려는 시도가 발생할 때 페이지를 복사해 수정하는 메커니즘을 말합니다. lazy copy라고도 합니다. 필요할 때만 복사해서 수정하기 때문에 메모리를 효과적으로 사용할 수 있습니다.

 

Zygote

Zygote는 앱이 시작될 때 사용되는 프로세스입니다. Zygote는 앱의 가상 머신을 포함한 초기 프로세스 상태를 복제하고 앱 프로세스를 생성합니다. 앱 프로세스를 생성할 때 코드와 리소스를 로드한 후, COW를 사용해서 프로세스 간에 동일한 메모리 페이지를 공유하도록 합니다.

 

 

 

https://developer.android.com/topic/performance/memory-management?hl=ko#kswapd

https://www.youtube.com/watch?v=w7K0jio8afM