로우 메모리 킬러 데몬

Android 로우 메모리 킬러 데몬(lmkd) 프로세스는 실행 중인 Android 시스템의 메모리 상태를 모니터링하고, 시스템 성능을 만족할 만한 수준으로 유지하기 위해 가장 필요성이 적은 프로세스를 종료하여 높은 메모리 압력에 반응합니다.

메모리 압력 정보

동시에 여러 프로세스를 실행하는 Android 시스템에서는 시스템 메모리가 소진되고 더 많은 메모리를 필요로 하는 프로세스가 눈에 띄게 지연될 수 있습니다. 시스템에서 메모리가 부족한 상태인 메모리 압력 상태에서는 중요하지 않은 프로세스를 제한하거나 종료하고, 중요하지 않은 캐시된 리소스 해제 프로세스를 요청하는 등의 조치를 통해 메모리를 확보해야 합니다.

지금까지 Android는 하드 코딩 값에 의존하는 강력한 메커니즘인 커널 내 로우 메모리 킬러(LMK) 드라이버를 사용하여 시스템 메모리 압력을 모니터링했습니다. 커널 4.12부터 LMK 드라이버는 업스트림 커널에서 삭제되고 사용자 공간 lmkd가 메모리 모니터링과 프로세스 종료 작업을 실행합니다.

압력 스톨 정보

Android 10 이상에서는 커널 압력 스톨 정보(PSI) 모니터를 사용하여 메모리 압력을 감지하는 새 lmkd 모드를 지원합니다. 업스트림 커널의 PSI 패치 세트(4.9 및 4.14 커널로 백포트됨)는 메모리 부족으로 작업이 지연되는 시간을 측정합니다. 이러한 지연은 사용자 환경에 직접적인 영향을 미치므로 메모리 압력 심각도를 결정하는 데 편리한 측정항목입니다. 업스트림 커널에는 권한이 있는 사용자 공간 프로세스(예: lmkd)가 이러한 지연의 기준점을 지정하고 기준점을 위반할 때 커널의 이벤트를 구독하도록 허용하는 PSI 모니터도 포함되어 있습니다.

PSI 모니터와 vmpressure 신호

메모리 압력 감지를 위해 커널에서 생성하고 lmkd에서 사용하는 vmpressure 신호에는 수많은 거짓양성이 포함되는 경우가 많으므로 lmkd는 필터링을 실행하여 메모리가 실제 압력을 받고 있는지 확인해야 합니다. 이로 인해 불필요한 lmkd wakeup과 추가 컴퓨팅 리소스 사용이 발생합니다. PSI 모니터를 사용하면 메모리 압력 감지가 더 정확해지고 필터링 오버헤드가 최소화됩니다.

PSI 모니터 사용

vmpressure 이벤트 대신 PSI 모니터를 사용하려면 ro.lmk.use_psi 속성을 구성하세요. 기본값은 true이며 PSI 모니터가 lmkd의 기본 메모리 압력 감지 메커니즘이 됩니다. PSI 모니터에는 커널 지원이 필요하므로 커널은 PSI 백포트 패치를 포함하고 PSI 지원이 사용 설정된 상태(CONFIG_PSI=y)로 컴파일되어야 합니다.

커널 내 LMK 드라이버의 단점

Android에서는 다음과 같은 여러 문제로 LMK 드라이버를 지원 중단합니다.

  • RAM이 부족한 기기는 적극적으로 조정해야 했지만 대규모 파일 지원 활성 페이지 캐시가 포함된 워크로드에서는 성능이 저하되었습니다. 성능 저하로 인해 스래싱이 발생하고 종료가 발생하지 않았습니다.
  • LMK 커널 드라이버는 메모리 압력에 따라 확장하지 않고 여유 메모리 제한에 의존했습니다.
  • 설계의 견고함으로 인해 파트너가 드라이버를 맞춤설정하여 기기에서 작동하도록 하는 경우가 많았습니다.
  • LMK 드라이버는 Slab Shrinker API에 연결되었는데 이 API는 타겟 검색 및 종료와 같은 부담이 큰 작업용으로 설계되지 않았으므로 vmscan 프로세스 속도가 느려졌습니다.

사용자 공간 lmkd

사용자 공간 lmkd는 커널 내 드라이버와 동일한 기능을 구현하지만 기존 커널 메커니즘을 사용하여 메모리 압력을 감지하고 예측합니다. 이러한 메커니즘에는 커널 생성 vmpressure 이벤트 또는 압력 스톨 정보(PSI) 모니터를 사용하여 메모리 압력 수준에 관한 알림을 받는 것과 메모리 cgroup 기능을 사용하여 프로세스 중요도에 따라 각 프로세스에 할당된 메모리 리소스를 제한하는 것이 포함됩니다.

Android 10에서 사용자 공간 lmkd 사용

Android 9 이상에서는 커널 내 LMK 드라이버가 감지되지 않으면 사용자 공간 lmkd가 활성화됩니다. 사용자 공간 lmkd에는 메모리 cgroup 커널 지원이 필요하므로 커널을 다음 구성 설정으로 컴파일해야 합니다.

CONFIG_ANDROID_LOW_MEMORY_KILLER=n
CONFIG_MEMCG=y
CONFIG_MEMCG_SWAP=y

종료 전략

사용자 공간 lmkdvmpressure 이벤트 또는 PSI 모니터, 심각도, 기타 힌트(예: 스왑 사용률)에 근거하여 종료 전략을 지원합니다. 종료 전략은 메모리 부족 기기와 고성능 기기 간에 다릅니다.

  • 메모리가 부족한 기기에서는 시스템이 더 높은 메모리 압력을 정상 작동 모드로 허용해야 합니다.
  • 고성능 기기에서 메모리 압력은 비정상적인 상황으로 보고 전체 성능에 영향을 미치기 전에 해결해야 합니다.

ro.config.low_ram 속성을 사용하여 종료 전략을 구성할 수 있습니다. 자세한 내용은 RAM 부족 구성을 참고하세요.

사용자 공간 lmkd는 커널 내 LMK 드라이버와 동일한 전략(즉, 여유 메모리 및 파일 캐시 기준점)을 사용하여 종료를 결정하는 기존 모드도 지원합니다. 기존 모드를 사용 설정하려면 ro.lmk.use_minfree_levels 속성을 true로 설정합니다.

lmkd 구성

다음 속성을 사용하여 특정 기기의 lmkd를 구성하세요.

속성 용도 기본값
ro.config.low_ram 기기가 RAM이 부족한 기기인지 고성능 기기인지 지정합니다. false
ro.lmk.use_psi vmpressure 이벤트 대신 PSI 모니터를 사용합니다. true
ro.lmk.use_minfree_levels 여유 메모리와 파일 캐시 기준점을 사용하여 프로세스 종료를 결정합니다. 즉, 커널 내 LMK 드라이버의 기능과 일치합니다. false
ro.lmk.low 낮은 수준 vmpressure에서 종료할 수 있는 프로세스의 최소 oom_adj 점수입니다. 1001
(사용 중지됨)
ro.lmk.medium 중간 수준 vmpressure에서 종료할 수 있는 프로세스의 최소 oom_adj 점수입니다. 800
(캐시되거나 필수가 아닌 서비스)
ro.lmk.critical 심각한 수준 vmpressure에서 종료할 수 있는 프로세스의 최소 oom_adj 점수입니다. 0
(모든 프로세스)
ro.lmk.critical_upgrade 심각한 수준으로 업그레이드할 수 있습니다. false
ro.lmk.upgrade_pressure 시스템이 너무 많이 스왑되어 수준이 업그레이드되는 최대 mem_pressure입니다. 100
(사용 중지됨)
ro.lmk.downgrade_pressure 아직 여유 메모리가 충분하므로 vmpressure 이벤트가 무시되는 최소 mem_pressure입니다. 100
(사용 중지됨)
ro.lmk.kill_heaviest_task 적합한 모든 작업을 종료(빠른 결정)하는 대신 가장 부담이 큰 적합한 작업을 종료합니다(최상의 결정). true
ro.lmk.kill_timeout_ms 추가 종료 작업이 실행되지 않을 때 종료 후 지속 시간(밀리초)입니다. 0
(사용 중지됨)
ro.lmk.debug lmkd 디버그 로그를 사용 설정합니다. false

기기 설정 예:

PRODUCT_PROPERTY_OVERRIDES += \
    ro.lmk.low=1001 \
    ro.lmk.medium=800 \
    ro.lmk.critical=0 \
    ro.lmk.critical_upgrade=false \
    ro.lmk.upgrade_pressure=100 \
    ro.lmk.downgrade_pressure=100 \
    ro.lmk.kill_heaviest_task=true

Android 11의 사용자 공간 lmkd

Android 11에서는 새 종료 전략을 도입하여 lmkd를 개선합니다. 종료 전략은 Android 10에서 도입된 메모리 압력 감지에 PSI 메커니즘을 사용합니다. Android 11의 lmkd는 메모리 부족 및 성능 저하를 방지하기 위해 메모리 리소스 사용 수준과 스래싱을 고려합니다. 이러한 종료 전략은 이전 전략을 대체하며 고성능 기기와 RAM이 부족한(Android Go) 기기에 모두 사용할 수 있습니다.

커널 요구사항

Android 11 기기의 경우 lmkd에 다음 커널 기능이 필요합니다.

  • PSI 패치를 포함하고 PSI를 사용 설정합니다(Android 일반 커널 4.9, 4.14, 4.19에서 사용 가능한 백포트).
  • PIDFD 지원 패치를 포함합니다(Android 일반 커널 4.9, 4.14, 4.19에서 사용 가능한 백포트).
  • RAM이 부족한 기기의 경우 메모리 cgroup을 포함합니다.

커널을 다음 구성 설정으로 컴파일해야 합니다.

CONFIG_PSI=y

Android 11에서 lmkd 구성

Android 11의 메모리 종료 전략은 아래에 나열된 조정 노브 및 기본값을 지원합니다. 이러한 기능은 고성능 및 RAM이 부족한 기기에서 모두 작동합니다.

속성 용도 기본값
고성능 RAM 부족
ro.lmk.psi_partial_stall_ms 메모리 부족 알림을 트리거하는 부분 PSI 스톨 기준점(밀리초)입니다. 기기가 메모리 압력 알림을 너무 늦게 받으면 이 값을 낮춰 이른 알림을 트리거합니다. 메모리 압력 알림이 불필요하게 트리거되면 이 값을 높여 기기가 노이즈에 덜 민감하도록 합니다. 70 200
ro.lmk.psi_complete_stall_ms 중요한 메모리 알림을 트리거하는 전체 PSI 스톨 기준점(밀리초)입니다. 기기가 중요한 메모리 압력 알림을 너무 늦게 받으면 이 값을 낮춰 이른 알림을 트리거합니다. 중요한 메모리 압력 알림이 불필요하게 트리거되면 이 값을 높여 기기가 노이즈에 덜 민감하도록 합니다. 700
ro.lmk.thrashing_limit 총 파일 지원 페이지 캐시 크기의 백분율로 표시되는 작업 세트 리폴트의 최대량입니다. 이 값을 초과하는 작업 세트 리폴트는 시스템이 페이지 캐시를 스래싱한다고 간주됨을 의미합니다. 메모리 압력으로 기기 성능이 영향을 받는 경우 이 값을 낮춰 스래싱을 제한합니다. 스래싱으로 인해 기기 성능이 불필요하게 저하되면 이 값을 높여 스래싱을 더 많이 허용합니다. 100 30
ro.lmk.thrashing_limit_decay 종료 후에도 시스템이 복구되지 않을 때 기준점을 낮추는 데 사용된 원래 기준점의 백분율로 표시되는 스래싱 기준점 하락입니다. 연속 스래싱으로 불필요한 종료가 생성되면 이 값을 낮춥니다. 종료 후 연속 스래싱에 대한 응답이 너무 느리면 이 값을 높입니다. 10 50
ro.lmk.swap_util_max 스왑 가능한 총 메모리의 백분율로 표시되는 스왑된 메모리의 최대량입니다. 스왑된 메모리가 이 제한을 초과하여 확장하면 시스템에서는 대다수 스왑 가능한 메모리를 스왑했고 여전히 압력을 받고 있다는 의미입니다. 이러한 상황은 대다수 스왑 가능한 메모리가 이미 스왑되었으므로 스와핑으로 완화할 수 없는 메모리 압력을 스왑 불가능한 할당에서 생성할 때 발생할 수 있습니다. 기본값은 100으로, 이 검사를 효과적으로 사용 중지합니다. 스왑 사용률은 높고 여유 스왑 수준은 ro.lmk.swap_free_low_percentage로 떨어지지 않는 동안 메모리 압력으로 기기 성능이 영향을 받는다면 이 값을 낮춰 스왑 사용률을 제한합니다. 100 100

다음 기존 조정 노브도 새 종료 전략과 호환됩니다.

속성 용도 기본값
고성능 RAM 부족
ro.lmk.swap_free_low_percentage 총 스왑 공간의 백분율로 표시되는 여유 스왑 수준입니다. 'lmkd'는 시스템에 스왑 공간이 부족한 것으로 간주하는 시점의 기준점으로 이 값을 사용합니다. 스왑 공간이 너무 많은 상태에서 'lmkd'가 종료되면 백분율을 낮춥니다. `lmkd` 종료가 너무 늦게 발생하여 OOM 종료가 발생하도록 허용하면 백분율을 높입니다. 20 10
ro.lmk.debug `lmkd` 디버그 로그가 사용 설정됩니다. 조정 중에 디버그를 사용 설정합니다. false