Android 17 이상에서는 Linux cgroup v2를 사용하여 애플리케이션 프로세스의 메모리 사용량을 모니터링하고 제한하는 시스템 서비스인 메모리 제한기를 지원합니다. 메모리 제한기는 개별 앱이 과도한 시스템 메모리를 소비하지 못하도록 방지하여 시스템 전체 메모리 압력을 줄이고 중요 프로세스의 적극적인 메모리 부족 (OOM) 종료를 방지합니다.
메커니즘
메모리 제한기는 활동 관리자 서비스 (AMS)와 통합되어 프로세스 수명 주기 이벤트와 상태 변경을 추적합니다. 메모리 제한기는 Linux 커널 cgroup v2 파일 시스템을 사용하여 메모리 제한을 적용합니다.
메모리 제한 도구를 사용하려면 기기 커널이 cgroup v2와 memory 컨트롤러를 지원해야 합니다. 이 서비스는 특히 다음 속성을 사용합니다.
memory.high- 소프트 한도입니다. 이 값을 초과하면 프로세스가 제한되고 커널이 프로세스에서 메모리를 회수하려고 시도합니다.
memory.swap.max- 프로세스에서 사용할 수 있는 스왑 공간의 양을 제한합니다.
앱에 미치는 영향
메모리 한도를 초과하지 않는 앱은 메모리 제한기에 영향을 받지 않습니다.
앱이 memory.high 한도를 초과하면 커널은 앱의 파일 지원 메모리를 삭제하고 익명 메모리를 스왑하여 앱을 한도 내로 유지합니다. 제거 및 스왑으로 인해 앱이 더 느리게 실행될 수 있습니다.
극단적으로 앱이 익명 메모리를 계속 할당하고 기기의 스왑 공간이 부족하면 앱이 메모리를 할당하지 못할 수 있으며 그 결과 비정상 종료될 가능성이 높습니다.
프로세스 모니터링
메모리 제한기는 기본적으로 앱 프로세스 (UID >= 10000)를 모니터링합니다. 시스템 프로세스는 일반적으로 핵심 시스템 안정성을 확인하는 데 도움이 되도록 제외됩니다.
메모리 제한기는 프로세스 상태에 따라 메모리 제한을 할당합니다.
표시되는 프로세스는 사용자에게 UI를 표시할 수 있는 상태에 있습니다. UI를 표시하는 동안 프로세스는 더 큰 RAM 작업 세트를 사용할 수 있으므로 더 관대한 메모리 제한이 허용됩니다.
표시되지 않는 프로세스는 활발하게 작업을 수행하지만 UI를 그리지 않는 상태에 있습니다. 이러한 작업에는 메모리가 사용되지만 UI를 표시할 때 필요한 메모리보다 적게 사용되므로 더 제한적인 한도가 부여됩니다.
다음 표에서는 특정 프로세스 상태를 메모리 제한에 매핑합니다.
| 프로세스 상태 | 메모리 한도 |
|---|---|
PERSISTENT | 제한 없음 |
PERSISTENT_UI | 제한 없음 |
TOP | 표시 |
BOUND_TOP | 표시 |
FOREGROUND_SERVICE | 표시 안함 |
BOUND_FOREGROUND_SERVICE | 표시 안함 |
IMPORTANT_FOREGROUND | 표시 |
IMPORTANT_BACKGROUND | 표시 안함 |
TRANSIENT_BACKGROUND | 표시 안함 |
BACKUP | 표시 안함 |
SERVICE | 표시 안함 |
RECEIVER | 표시 안함 |
TOP_SLEEPING | 표시 |
HEAVY_WEIGHT | 표시 안함 |
HOME | 표시 안함 |
LAST_ACTIVITY | 표시 안함 |
CACHED_ACTIVITY | 캐시됨 |
CACHED_ACTIVITY_CLIENT | 캐시됨 |
CACHED_RECENT | 캐시됨 |
CACHED_EMPTY | 캐시됨 |
캐시된 상태에서 프로세스는 고정된 후 최대한 회수됩니다.
프로세스가 할당된 memory.high 한도를 초과하면 메모리 제한기가 이벤트를 감지하고 메모리 프로필 캡처 또는 statsd에 비정상 로깅과 같은 디버깅 작업을 트리거할 수 있습니다.
구성
vendor 파티션에 있는 XML 파일을 사용하여 메모리 제한기 구성 구성을 사용하면 기기의 특정 메모리 제약에 따라 절대 메모리 한도를 조정할 수 있습니다.
파일 경로:
/vendor/etc/memory-limiter-config.xml기본 구성: 구성 파일을 찾을 수 없거나 읽을 수 없거나 잘못된 경우 메모리 제한기가 사용 중지됩니다.
XML 형식
구성 파일은 memory-limiter-config.xsd에 정의된 스키마를 따릅니다. 이 파일을 사용하면 여러 제한 집합을 정의할 수 있으며 서비스는 기기에서 사용 가능한 RAM을 기반으로 가장 적합한 집합을 선택합니다. 모든 메모리 값은 메비바이트 (MiB) 단위로 정의됩니다.
<MemoryLimiterConfig>
<version>1</version>
<configList>
<limitSet>
<!-- Limits for a phone with at least 14G of ram: 8G/4G/4G/4G -->
<minimumRequiredMemTotal>14336</minimumRequiredMemTotal>
<memVisible>8192</memVisible>
<memNotVisible>4096</memNotVisible>
<swapVisible>4096</swapVisible>
<swapNotVisible>4096</swapNotVisible>
</limitSet>
</configList>
</MemoryLimiterConfig>
version- 구성 버전을 식별하는 양의 정수입니다. 1이어야 합니다.
minimumRequiredMemTotal- 이 한도 집합이 유효하려면 필요한 최소 사용 가능한 시스템 메모리입니다.
memVisible- 표시되는 프로세스에 허용되는 메모리 한도 (
memory.high) memNotVisible- 표시되지 않는 프로세스에 허용되는 메모리 제한 (
memory.high)입니다. swapVisible- 표시되는 프로세스에 허용된 스왑 한도 (
memory.swap.max) swapNotVisible- 보이지 않는 프로세스에 허용된 스왑 제한 (
memory.swap.max)
기기 메모리 제한 가이드라인
기기의 메모리 제한을 구성할 때는 다음 가이드라인을 고려하세요.
하드웨어 기능에 맞게 제한 조정: 기기 OEM은 기기 하드웨어 기능에 맞게 제한을 설정할 수 있습니다. Android에서는 다음 범위를 권장합니다.
- 표시되는 프로세스: 총 실제 RAM의 1/2 이상, 2/3 이하
- 보이지 않는 프로세스: 전체 실제 RAM의 1/4~1/3 OEM은 기기 기능과 사용 사례에 따라 다르게 결정할 수 있습니다.
앱의 런타임 API 없음: Android 17 (SDK 37)부터 앱에는 런타임에 메모리 제한을 쿼리하는 API가 없습니다. OEM은 이를 고려하여 한도를 너무 낮게 설정하지 않아야 하며, 합리적인 사용 사례에서 앱이 한도에 도달하지 않도록 해야 합니다.
범용 구성: 한도는 사전 설치된 앱을 포함하여 기기의 모든 앱 프로세스에 적용됩니다. 이러한 제한에서 특정 앱을 제외하는 허용 목록은 없습니다.
구성 수정
시스템 전체 제한을 변경하려면 다음 단계를 따르세요.
/vendor/etc/memory-limiter-config.xml수정- 변경사항이 적용되도록 기기를 재부팅하거나
system_server을 다시 시작합니다.
셸 명령어
am memory-limiter 명령어를 사용하면 개발자와 개발자가 런타임에 개발 및 테스트를 위해 서비스와 상호작용할 수 있습니다.
am memory-limiter <SUB-COMMAND>상태
status 하위 명령어는 메모리 제한기의 작동 상태를 보고합니다.
adb shell am memory-limiter status출력 예시:
Memory limiter
enabled monitoring=true ignored=none
visibleMem=1948MB visibleSwap=974MB
notVisibleMem=974MB notVisibleSwap=487MB
started=36 watched=36 watch-failed=0
events=0 processes=36 process-hwm=36
출력의 주요 필드는 다음과 같습니다.
monitoring- 제한기가 프로세스를 적극적으로 감시하는지 여부를 나타냅니다.
visibleMem및notVisibleMem- 각 상태에 대해 계산된 절대 메모리 한도를 표시합니다.
events- 프로세스가 한도를 초과한 횟수입니다.
processes- 모니터링된 프로세스 수입니다.
ignore
ignore 하위 명령어는 제한에서 UID 또는 모든 프로세스를 일시적으로 제외합니다. 이 작업은 성능 테스트를 하거나 특정 앱이 한도를 초과하도록 허용할 때 유용합니다.
adb shell am memory-limiter ignore 10087 // Ignore a specific UIDadb shell am memory-limiter ignore all // Ignore all processes (effectively disables limiting)adb shell am memory-limiter ignore none // Resume normal operation
수동
manual 하위 명령어는 특정 프로세스(프로세스 ID 또는 PID별)의 계산된 한도를 메가바이트 (MB) 단위의 맞춤 절대값으로 재정의합니다.
adb shell am memory-limiter manual 1234 1024 // Set a 1024 MB limit for PID 1234adb shell am memory-limiter manual 1234 none // Remove the manual override for PID 1234
수동 재정의는 프로세스의 수명 주기에만 적용됩니다. 프로세스가 다시 시작되면 상태에 따라 기본 한도로 돌아갑니다.