OOM(Out Of Memory)가 발생하는 이유

Linux에서는 프로세스 실행 시 필요한 메모리를 바로 할당하는 것이 아니라 메모리를 주었다는 것을 저장하는 Memory Commit 정책을 가지고 있다. 실제 메모리 할당은 프로세스가 실행되면서 메모리가 필요할 때 이루어진다.

그리고 Linux는 Overcommit를 허용하는데, 이는 커밋된 메모리가 실제 가용 메모리보다 더 큰 것을 뜻한다. Overcommit 덕분에 메모리 사용량이 큰 프로세스가 있어도 실행될 수가 있다. 그런데 Overcommit이 된 상태에서 프로세스에게 실제 메모리 할당이 되면 가용 메모리보다 더 큰 메모리를 할당할 수도 있는데, 이 때 OOM(Out Of Memory)이 발생하기 때문에 Overcommit은 OOM의 주요 원인으로 손꼽힌다.

OOM Killer과 OOM Score

OOM이 발생하면 메모리 확보를 위해 프로세스를 강제로 종료 시키는 OOM Killer가 실행된다. OOM Killer이 프로세스를 종료할 때 당연히 무작위로 종료하는 것은 아니고, OOM Score에 따라서 종료될 프로세스가 결정된다. OOM Score은 0~1000 사이의 값을 가지고, 값이 클 수록 종료 우선순위가 높아진다. 따라서 OOM Killer는 OOM Score이 높은 순서대로 프로세스를 종료한다.

OOM Score은 oom_badness()를 통해 계산된다. Heuristic하게 계산되는 점수인 만큼 시간이 지나면서 점수 계산 방법이 여러 번 바뀌었던 것 같은데 현재는 기본적으로 메모리 사용량이 높을 수록 OOM Score이 높아진다.

OOM Killer가 실행됐을 때 로그는 /var/log/syslog 에서 볼 수 있다.

OOM Score 확인법

Linux에서 프로세스의 OOM Score 관련 값이 저장되어 있는 경로는 다음과 같다.

  • /proc/{PID}/oom_score : 프로세스의 OOM Score(0~1000)
  • /proc/{PID}/oom_adj : OOM Score 조정값(-17 ~ 17). Deprecated
  • /proc/{PID}/oom_score_adj : OOM Score 조정값(-1000 ~ 1000)

oom_score_adj 값은 OOM Score 조정 값이다. OOM Score를 계산하는 oom_badness()를 보면 마지막에 adj이 OOM Score에 더해지는 것을 볼 수 있다. oom_score_adj 값이 -1000이면 OOM Score LONG_MIN 값을 가져서 종료되지 않는다.

따라서 하나의 머신에서 서버를 포함한 여러 개의 프로세스가 실행되어 있는데, OOM이 발생해도 OOM Killer가 서버 프로세스를 종료하지 않도록 하기 위해서는 서버 프로세스의 oom_score_adj 값을 -1000으로 바꾸면 된다.

예시

  • OOM Score 확인
$ cat /proc/2533032/oom_score
2
  • oom_score_adj 확인
$ cat /proc/2533032/oom_score_adj
-998
  • oom_score_adj
$ sudo echo 0 > oom_score_adj
  • oom_score_adj 값을 -998에서 0으로 변경

Reference

 

+ Recent posts