한 가지 “남은 메모리” 숫자로는 설명할 수 없습니다
| 질문 | 확인할 대상 |
|---|---|
| 프로세스의 주소 공간이 부족합니까? | 가상 주소 배치·mapping·rlimit·ABI 폭을 봅니다. |
| 사용 가능한 물리 메모리가 부족합니까? | 회수 가능한 cache·anonymous memory·swap·zone 상태 등을 봅니다. |
| 큰 연속 공간이 필요합니까? | 총량뿐 아니라 fragmentation·할당 order·CMA 등 요청 조건을 봅니다. |
| 그 작업에 허용된 한도를 넘었습니까? | cgroup·컨테이너·서비스에 적용된 제한을 봅니다. |
malloc이 성공했다고 그 크기만큼 모든 물리 페이지를 즉시 독점 확보했다는 뜻은 아닙니다. 실제 page fault와 사용 과정, overcommit 정책에 따라 시점이 다를 수 있습니다. 반대로 free 메모리가 조금 있다고 어떤 GFP 조건의 kernel 할당도 성공하는 것은 아닙니다. 가상 메모리와 page 회수 page 할당 조건
호스트 전체와 내 cgroup의 여유는 다를 수 있습니다
cgroup v2에서는 memory.current로 사용량을 보고 memory.max 등의 제한을 확인합니다. memory.high는 주로 회수·throttling 경로를 유도하는 경계이며 memory.max와 같은 hard limit로 읽으면 안 됩니다. memory.events의 high·max·oom·oom_kill 등의 변화도 의미가 다릅니다. cgroup v2 memory controller
cat /proc/meminfo
cat /proc/self/cgroup
cat /sys/fs/cgroup/example/memory.current
cat /sys/fs/cgroup/example/memory.eventsexample은 실제 cgroup 경로로 바꾸는 관찰 예입니다. cgroup v1이나 mount 구성에 따라 파일이 다릅니다. 컨테이너 안에서 보이는 경로와 호스트 경로도 구분해야 합니다.
Android lmkd와 kernel OOM killer는 같은 코드가 아닙니다
- 메모리 압박 관측
회수 지연·pressure·사용량·한도 등을 관찰합니다.
어느 정책 주체가 반응했는지 확인합니다.
- 정책과 선택
kernel의 OOM 처리인지 Android lmkd의 선택인지 구분합니다.
해당 주체의 로그와 선택 기준을 확인합니다.
- 프로세스 종료 또는 실패
어떤 process·cgroup이 영향을 받았는지 확인합니다.
원래 allocation·workload·제한과 연결합니다.
- 원인 정리
누수·과도한 buffer·한도·재현 조건을 비교합니다.
화살표는 조사 순서입니다. 모든 메모리 압박이 반드시 OOM kill로 이어진다는 뜻은 아닙니다.
Android lmkd는 사용자 공간 daemon이며 Android의 process 중요도와 memory pressure 정보를 활용합니다. 옛 lowmemorykiller kernel driver 설명을 최근 모든 Android 기기에 그대로 적용하지 않습니다. 특정 앱이 종료됐다는 사실만으로 Java heap의 OutOfMemoryError와도 동일시하지 않습니다. Android lmkd의 동작
원인을 정한 뒤 할당과 수명을 고칩니다
| 문제 | 수정 방향을 정할 증거 |
|---|---|
| 누수 의심 | 요청 반복 후 살아 있는 객체·buffer 수가 계속 증가하는지 확인합니다. |
| 순간적인 peak | 여러 pipeline이 겹치는 시점과 buffer 개수를 확인합니다. |
| 연속 공간 문제 | 요청 크기·order·DMA 요구 조건과 실제 fragmentation을 확인합니다. |
| cgroup 제한 | 애플리케이션의 요구량과 의도한 서비스 한도를 대조합니다. |
무조건 cache를 비우거나 OOM 대상 선택 값을 바꾸는 것으로 원인을 덮지 않습니다. 해제 후에도 device·worker가 buffer를 쓰는 문제는 누수를 줄이려다 use-after-free로 바뀔 수 있으므로 수명부터 맞춰야 합니다.