Android 17 이상에서는 데몬 구성, 조정 가능 항목, 지속적인 스왑 또는 ZRAM 유지관리 작업을 처리하는 시스템 데몬인 메모리 관리 데몬(mmd)을 지원합니다.
배경
mmd 도입 전에는 Android의 ZRAM 구성이 단편화되어 맞춤설정이 제한적이었습니다. mmd는 ZRAM 관리를 중앙 집중화하여 이 문제를 해결하고, 더 정교한 구성 논리를 지원하며, 새로운 기능과 아키텍처 개선사항을 더 쉽게 추가할 수 있습니다.
mmd는 Java 기반 system_server 프로세스와 커널 수준 스왑 또는 메모리 관리 간의 명확한 관심사 분리도 설정합니다.
아키텍처 및 ZRAM 관리
부팅 완료 시 (즉, sys.boot_completed=1) mmd_setup은 지정된 매개변수로 ZRAM을 구성하려고 시도합니다. ZRAM 설정이 완료되면 시스템은 지속적인 유지관리 작업을 처리하는 mmd 서비스를 사용 설정합니다.
mmd 프로젝트에서 유지보수 작업은 IMmd 인터페이스를 사용하여 바인더 요청을 mmd에 전송하여 system_server에서 시작됩니다.
mmd는 자체 내부 정책 엔진에 따라 ZRAM 다시 쓰기, 재압축, 프로세스별 다시 쓰기를 실행하는 유지관리 작업을 처리합니다. ActivityManagerService의 일정과 ZRAM 유지관리 정책은 모두 시스템 속성을 사용하여 구성할 수 있습니다.
시스템 서버 통합 (system_server)
Java 기반 system_server 프로세스는 mmd가 호출되는 시점을 결정합니다. 이 프로세스는 전역 유지관리 스윕을 타겟팅된 앱별 메모리 최적화와 분리합니다.
일반 사후 처리 유지보수
전역 ZRAM 유지 관리는 com.android.server.memory.ZramMaintenance를 사용하는 ActivityManagerService에 의해 실행됩니다.

그림 1. ZRAM 유지보수 일정 관리 흐름
- 일정 관리 엔진:
ZramMaintenance는 Android의JobScheduler에 주기적인 백그라운드 작업을 등록합니다. - 작업 제약 조건: 포그라운드 UI 끊김 현상이나 CPU 경합을 방지하기 위해 작업은
setRequiresDeviceIdle(true)및setRequiresBatteryNotLow(true)로 명시적으로 구성됩니다. - 바인더 트리거: 스케줄러가
onStartJob()를 실행하면system_server가mmd.doZramMaintenanceAsync()를 호출합니다. 이는 단방향 비동기 바인더 호출입니다.system_server는 유지관리 스윕이 완료될 때까지 대기하지 않습니다.mmd는 재압축과 쓰기 작업을 순차적으로 실행하기 위해 이를 백그라운드 작업자 스레드에 대기열로 추가합니다.
프로세스별 쓰기
타겟팅된 프로세스별 메모리 삭제는 ActivityManagerService에서 com.android.server.am.CachedAppOptimizer를 사용하여 관리합니다.

그림 2. 프로세스별 mmd 쓰기 흐름
프로세스가 백그라운드 캐시 상태로 전환되면 ActivityManager가 메모리 압축을 실행합니다. 프로세스의 메모리 부족 종료가 사용자에게 표시되는 경우, 즉 프로세스가 활동을 호스팅하고 프로세스의 메모리 사용 공간이 ZRAM 프로세스별 쓰기 복구로 인해 0에 가까워지면 시스템은 다음 단계를 따릅니다.
- 압축 후
CachedAppOptimizer는 지연된 메시지 (ZRAM_WRITEBACK_MSG)를 내부 압축 핸들러에 게시합니다(mZramWritebackWaitSeconds에 의해 지연됨). - 지연 시간이 만료되면 ActivityManager가 보안 프로세스 파일 설명자
pidfd를 엽니다. - 시스템 서버가
mmd.asyncWritebackProcessZramMemory(pfd, callback)를 호출합니다. mmd는 프로세스별 쓰기 ioctl을 실행하고IMmdProcessWritebackCallback를 사용하여 다시 보고합니다. 성공하면 ActivityManager가 프로세스 레코드 (setIsZramWrittenBack(app, true))에 플래그를 지정하여 프로세스의oom_score_adj를 부스팅하고FrameworkStatsLog.ZRAM_WRITEBACK_EVENT에 측정항목을 로깅합니다.
프로세스별 프리페치
사용자가 이전에 캐시된 앱을 다시 실행하면 (UNFREEZE_REASON_ACTIVITY로 인해 고정 해제됨) ActivityManager는 지원 저장소에서 발생하는 심각한 페이지 오류로 인한 앱 시작 지연 시간을 최소화합니다.
CachedAppOptimizer는 고정 해제 이벤트를 가로채고prefetchZram(app)를 호출합니다.- 시스템 서버는
mmd.asyncPrefetchProcessZramMemory(pfd)를 사용하여 Binder 전반에 앱의pidfd를 디스패치합니다.mmd는ZRAM_ANDROID_IOC_PROCESS_PREFETCHioctl을 실행하여 앱의 기본 UI 스레드가 초기화되는 동안 스왑된 페이지를 RAM에 비동기식으로 미리 가져오도록 커널에 지시합니다.
유지보수 및 사후 처리 작업 개요
이 섹션에서는 mmd가 스왑 공간과 시스템 메모리를 최적화하기 위해 실행하는 백그라운드 유지관리 작업과 후처리 작업을 설명합니다.
mmd의 유지보수
mmd에서 유지관리는 활성 사용자 포그라운드 성능에 영향을 주지 않고 스왑 공간과 실제 메모리 사용률을 최적화하는 예약된 백그라운드 유지관리 스윕을 의미합니다. 지속적인 동기 스윕 (심각한 CPU 절전 모드 해제 및 UI 버벅거림을 유발함)을 실행하는 대신 유지관리는 비동기적으로 실행됩니다.
system_server는 바인더 전반에서 주기적으로doZramMaintenanceAsync()을 실행합니다.mmd는 요청을 백그라운드 작업 대기열LowPrioWorkItem::ZramMaintenance에 배치합니다.mmd에는 우선순위가 높은 대기열과 우선순위가 낮은 대기열을 모두 관리하는 단일 작업자 스레드가 있습니다. 우선순위가 높은 작업 항목 (예: 프로세스별 미리 가져오기)이 먼저 처리되며 우선순위가 낮은 작업 항목을 선점할 수 있습니다. 유지보수 및 프로세스별 쓰기 작업은 우선순위가 낮은 작업 항목으로 작동합니다. 팝되면 작업자 스레드는 두 가지 기본 유지보수 작업을 순차적으로 실행합니다.ZRAM 재압축: 기존 스왑 페이지를 검색하고 비율이 높은 보조 압축 알고리즘(예:
zstd)을 사용하여 유휴 페이지를 재압축합니다.ZRAM 쓰기: 유휴 페이지를 검색하고
/data의 파일에서 루프 기기를 지원 플래시 저장소로 RAM에서 완전히 삭제합니다.
ZRAM의 후처리 작업
Linux 커널 ZRAM 모듈과 mmd 아키텍처에서 후처리 작업은 커널의 표준 회수 경로(kswapd 또는 압축)에 의해 이미 스왑된 메모리 페이지에 후에 적용되는 비동기 변환입니다.
페이지가 처음 스왑될 때 시스템은 속도를 우선시합니다. 빠른 기본 압축 알고리즘 (예: lz4)을 사용하고 압축된 페이지를 RAM에 저장합니다. 하지만 시간이 지남에 따라 스왑된 많은 페이지가 콜드 또는 유휴 상태가 됩니다. 예를 들어 몇 시간 동안 재개되지 않은 백그라운드 캐시 앱이 있습니다. 빠르고 가볍게 압축된 ZRAM에 콜드 페이지를 남기는 것은 비효율적입니다.
후처리 파이프라인
mmd는 이러한 페이지를 최적화하기 위해 다단계 후처리 수명 주기를 구현합니다.

그림 3. mmd 페이지 수명 주기
1단계: 초기 스왑 아웃 (빠른 압축): 메모리는 먼저 kswapd 또는 앱 압축을 통해 회수됩니다. 일반적으로 이 첫 번째 회수는
lz4와 같은 빠른 압축 알고리즘을 사용하여 실행되며 콘텐츠는 RAM에 저장됩니다.2단계: 유휴 상태 표시 (에이징 및 추적):
mmd유휴 상태 추적은 커널 메모리 추적 (CONFIG_ZRAM_TRACK_ENTRY_ACTIME)에 액세스하거나 소프트웨어 유휴 상태 마커를 사용하여 페이지가 터치되지 않은 시간을 추적합니다.3단계: 후처리 1 - 재압축 (메모리 내 회수): 재압축 유휴 기간 (
min_idle_seconds~max_idle_seconds)에 도달한 페이지는 재압축됩니다.mmd는/sys/block/zram0/recompress에 써서 커널에lz4페이지를 압축 해제하고zstd를 사용하여 다시 압축하도록 지시합니다. 이렇게 하면 플래시 쓰기 마모 없이 실제 RAM이 회수됩니다.4단계: 후처리 2 - 쓰기 (플래시 저장소로 삭제): 메모리 압력이 계속되고 페이지가 쓰기 유휴 기간 (일반적으로 20시간 이상)에 도달하면
mmd가 쓰기를 트리거합니다.mmd는/sys/block/zram0/idle및/sys/block/zram0/writeback에 써서 압축된 페이지를 RAM에서 지원 플래시 스토리지로 완전히 제거합니다.
ZRAM 설정 구성
mmd는 다음 ZRAM 설정 속성을 로드하고 처리합니다.
| 속성 | 용도 | 기본값 |
|---|---|---|
mmd.zram.enabled |
mmd ZRAM 설정이 사용 설정되어 있는지 여부입니다. |
false |
mmd.zram.num_devices |
구성할 ZRAM 기기 수입니다. N의 경우 시스템에서 sys.boot_completed=1을 설정하기 전에 zram0~zram<N-1> 기기가 있어야 합니다.
ZRAM별 기기 목록의 속성은 기기별로 구성할 수 있습니다.
|
1 |
mmd.zram.device_priority |
swapon 호출 시 전달할 우선순위 값입니다. |
설정되지 않음 |
mmd.zram.comp_algorithm |
ZRAM 압축 알고리즘입니다. 지정하지 않으면 커널 기본 압축 알고리즘이 사용됩니다. | 설정되지 않음 |
mmd.zram.size |
바이트 단위의 zRAM 기기 크기 또는 기기 RAM 크기의 비율(예: 75%)입니다.
|
50% |
mmd.zram.writeback.enabled |
ZRAM 쓰기 지원을 사용 설정할지 여부입니다. | false |
mmd.zram.writeback.device_size |
바이트 단위 또는 데이터 파티션 비율로 표시된 쓰기 지원 기기의 크기입니다. 실제 기기 크기는 데이터 파티션의 사용 가능한 공간에 따라 조정할 수 있습니다. | 1073741824 (1GiB) |
mmd.zram.writeback.min_free_space_mib |
쓰기 장치가 설정된 후 사용할 수 있어야 하는 최소 여유 공간(MiB)입니다. | 1536 (1.5GiB) |
mmd.zram.writeback.use_nr_tags_prop |
true은 mmd.zram.writeback.nr_tags의 값을 사용하여 ZRAM 쓰기 지원 루프 기기의 대기열 깊이를 구성합니다. 이는 공급업체 SELinux 정책이 mmd가 /data를 지원하는 블록 기기의 nr_tags를 직접 읽도록 구성할 수 없는 상황의 해결 방법입니다.
|
false |
mmd.zram.writeback.nr_tags |
mmd.zram.writeback.use_nr_tags_prop를 참조하세요. |
설정되지 않음 |
mmd.zram.recompression.enabled |
ZRAM 재압축 기능을 사용 설정할지 여부입니다. | false |
mmd.zram.recompression.algorithm |
보조 ZRAM 재압축 알고리즘 | zstd |
ZRAM별 기기 속성
mmd.zram.num_devices이 1보다 큰 경우 속성을 정확히 mmd.zram.num_devices 요소를 포함하는 쉼표로 구분된 값으로 설정하여 ZRAM 기기별로 특정 속성을 선택적으로 구성할 수 있습니다.
이러한 속성에는 다음이 포함됩니다.
mmd.zram.sizemmd.zram.comp_algorithmmmd.zram.device_prioritymmd.zram.recompression.enabledmmd.zram.recompression.huge_idle.enabledmmd.zram.recompression.idle.enabledmmd.zram.recompression.huge.enabledmmd.zram.recompression.threshold_bytesmmd.zram.recompression.algorithmmmd.zram.writeback.device_sizemmd.zram.writeback.huge_idle.enabledmmd.zram.writeback.idle.enabledmmd.zram.writeback.huge.enabled
기존 ZRAM 설정 지원 중단
swapon_all는 Android에서 ZRAM과 디스크 기반 스왑 공간을 설정하는 데 여전히 사용할 수 있지만 mmd은 더 쉬운 구성과 ZRAM 재압축과 같은 고급 기능을 위해 ZRAM 관리에 선호되는 접근 방식입니다.
mmd.zram.enabled에 의해 mmd ZRAM 설정이 사용 설정된 경우:
swapon_all구현의 ZRAM 설정이 no-op이 됩니다.- 오버레이
config.xml파일의config_zramWriteback및ro.zram.*쓰기 시스템 속성과 같은 기존 ZRAM 구성은 무시됩니다.
ZRAM 유지관리 조정 가능
ZRAM 유지관리는 기본적으로 작동해야 하며 이 섹션의 시스템 속성을 사용하여 추가로 미세 조정할 수 있습니다.
ZRAM 유지보수 일정
이러한 속성은 system_server에 의해 ZRAM 유지관리 작업이 예약되는 방식과 시기를 제어합니다.
| 속성 | 용도 | 기본값 |
|---|---|---|
mm.zram.maintenance.first_delay_seconds |
첫 번째 ZRAM 유지보수가 시작되기 전 지연 시간입니다. | 3600 (1시간) |
mm.zram.maintenance.periodic_delay_seconds |
후속 ZRAM 유지보수 예약 간 지연 시간입니다. | 3600 (1시간) |
mm.zram.maintenance.require_device_idle |
기기가 유휴 상태일 때만 ZRAM 유지보수를 시작할지 여부 | true |
mm.zram.maintenance.require_battery_not_low |
ZRAM 유지보수를 시작하기 전에 배터리 부족 상태가 아닌지 확인해야 하는지 여부 | true |
ZRAM 쓰기 정책
다음 매개변수는 지원 기기에 메모리가 기록되는 시점과 메모리 유형을 제어합니다.
| 속성 | 용도 | 기본값 |
|---|---|---|
mmd.zram.writeback.backoff_seconds |
마지막 쓰기 작업 이후의 백오프 시간입니다. | 600 (10분) |
mmd.zram.writeback.min_idle_seconds |
mmd.zram.writeback.max_idle_seconds와 결합하여 메모리 사용률에 따라 페이지가 쓰기 복구될 수 있는 유휴 시간을 계산합니다. 계산된 유휴 연령은 메모리 압력이 없는 동안 작업을 최소화하기 위해 두 매개변수 사이에서 지수적으로 보간됩니다.
|
72000 (20시간) |
mmd.zram.writeback.max_idle_seconds |
메모리 사용률에 따라 유휴 페이지 기간을 동적으로 계산하는 데 사용되는 최대 시간(초)입니다. | 90000 (25시간) |
mmd.zram.writeback.huge.enabled |
HUGE 페이지 쓰기 작업을 사용 설정할지 여부입니다. |
false |
mmd.zram.writeback.idle.enabled |
IDLE 페이지 쓰기 작업을 사용 설정할지 여부입니다. |
true |
mmd.zram.writeback.huge_idle.enabled |
HUGE_IDLE 페이지 쓰기 작업을 사용 설정할지 여부입니다. |
true |
mmd.zram.writeback.min_bytes |
유휴 쓰기 한 라운드에서 다시 쓸 최소 바이트 수입니다. | 5242880 (5MiB) |
mmd.zram.writeback.max_bytes |
유휴 쓰기 한 라운드에서 다시 쓸 최대 바이트 수입니다. | 314572800 (300MiB) |
mmd.zram.writeback.max_bytes_per_day |
24시간 동안 다시 쓸 최대 바이트 수입니다. | 25769803776 (24GiB) |
mmd.zram.writeback.limit.enabled |
일일 쓰기 백 예산 한도 회계를 사용 설정할지 여부입니다. | true |
ZRAM 재압축 정책
다음 매개변수는 메모리가 언제 어떤 유형으로 재압축되는지 제어합니다.
| 속성 | 용도 | 기본값 |
|---|---|---|
mmd.zram.recompression.backoff_seconds |
마지막 재압축 이후의 백오프 시간입니다. | 1800 (30분) |
mmd.zram.recompression.min_idle_seconds |
메모리 사용률 비율에 따라 재압축 대상 페이지의 유휴 기간을 계산하기 위해 mmd.zram.recompression.max_idle_seconds와 결합됩니다. 계산된 유휴 시간은 메모리 압력이 없는 동안 작업을 최소화하기 위해 두 매개변수 간에 지수적으로 보간됩니다.
|
7200 (2시간) |
mmd.zram.recompression.max_idle_seconds |
동적으로 유휴 페이지 기간을 계산하는 데 사용되는 최대 시간(초)입니다. | 14400 (4시간) |
mmd.zram.recompression.threshold_bytes |
재압축을 고려하는 ZRAM 페이지의 최소 크기(바이트)입니다. | 1024 (1KiB) |
mmd.zram.recompression.huge.enabled |
HUGE 페이지 재압축을 사용 설정할지 여부입니다. |
true |
mmd.zram.recompression.idle.enabled |
IDLE 페이지 재압축을 사용 설정할지 여부입니다. |
true |
mmd.zram.recompression.huge_idle.enabled |
HUGE_IDLE 페이지 재압축을 사용 설정할지 여부입니다. |
true |
ZRAM 유휴 페이지 추적
mmd ZRAM 유지관리에서는 마지막으로 액세스한 후 경과한 시간을 기준으로 ZRAM 페이지를 유휴 상태로 표시합니다. 이 기능을 사용하려면 CONFIG_ZRAM_TRACK_ENTRY_ACTIME 또는 CONFIG_ZRAM_MEMORY_TRACKING 커널 구성을 사용 설정해야 합니다. CONFIG_ZRAM_TRACK_ENTRY_ACTIME는 GKI 커널 6.18 이상에서 기본적으로 사용 설정됩니다. 이전 커널에서는 메모리 오버헤드가 있으며 기본적으로 사용 설정되지 않습니다.
커널 구성이 사용 설정되지 않으면 mmd ZRAM 유지관리에서 유휴 ZRAM 페이지를 추적하는 소프트웨어 대체 로직으로 대체됩니다.
mmd가 시작될 때 모든 ZRAM 페이지를 유휴 상태로 표시필요한 백오프 기간이 지날 때까지 다음 ZRAM 유지보수를 건너뜁니다.
ZRAM 쓰기 또는 유휴 페이지 재압축 쓰기 제한으로 인해 유휴 페이지가 남아 있는 경우
mmd는 새 페이지를 유휴로 표시하지 않고 (4단계 건너뛰기) 다음 유지관리에서 페이지를 다시 씁니다.모든 유휴 페이지가 다시 작성되면 모든 ZRAM 페이지를 다시 유휴로 표시하고 2단계로 돌아갑니다. ZRAM 쓰기 지원이 사용 중지된 경우
mmd는 재압축 유휴 기간 후 ZRAM 재압축이 발생할 때 모든 ZRAM 페이지를 유휴로 표시합니다.
문제 해결 및 검증 안내
다음 검증 단계와 문제 해결 절차를 사용하여 mmd 및 ZRAM 작업을 확인하고 진단합니다.
ZRAM 설정 검사
mmd이 부팅 중에 ZRAM을 성공적으로 구성했는지 확인하려면 다음을 실행하세요.
활성 압축 알고리즘과 디스크 크기를 확인합니다.
cat /sys/block/zram0/comp_algorithm cat /sys/block/zram0/disksizemmd시스템 속성 및 실행 중인 서비스 상태를 확인합니다.getprop | grep mmd.zram dumpsys -l | grep mmd
ZRAM 유지관리 및 쓰기 검증
ZRAM 쓰기 및 재압축 유지관리 작업이 작동하는지 확인합니다.
지원 블록 기기 상태를 확인합니다.
cat /sys/block/zram0/bd_stat/sys/block/zram0/mm_stat를 모니터링하여 재압축 효율성을 확인합니다. 압축된 데이터 크기의 변경사항은 유지관리 주기가 지난 후에 표시됩니다.
프로세스별 쓰기 검사
다음은 프로세스별 쓰기 캐시가 작동하는지 확인하는 데 사용할 수 있습니다.
- 성공적인 쓰기 로그 또는 실패 진단을 위해
adb logcat -s mmd를 확인합니다.
일반적인 문제 및 진단
다음은 사용자가 겪을 수 있는 일반적인 오류 상황입니다.
WritebackDailyLimitExceeded: 이 오류는mmd.zram.writeback.max_bytes_per_day할당량에 도달했음을 나타냅니다. 이 경우mmd는 24시간 순환 기간이 진행될 때까지 유휴 쓰기 백을 일시중지합니다.Process prefetch or writeback failed: 이 오류는 ioctl이 실패할 때 logcat에서 관찰할 수 있습니다. 일반적인 원인은 다음과 같습니다.EBADF또는ESRCH:mmd가 커널에pidfd을 디스패치하기 전에 타겟 프로세스가 종료되었습니다.ENOSPC: 지원 스토리지 파티션이 가득 찼거나 루프 기기 대기열이 소진되었습니다.
- ZRAM이 설정되지 않음:
mmd가 부팅 시 ZRAM을 구성하지 못하면 레거시swapon_all또는 공급업체 init 스크립트가mmd가 실행되기 전에/dev/block/zram0를 잠갔기 때문일 수 있습니다.