리눅스 서버에서 프로그램을 실행하거나 새로운 프로세스를 생성하려는데 갑자기 Cannot allocate memory 오류가 발생하는 경우가 있습니다. SSH 접속은 정상적으로 되지만 명령어 실행이 실패하거나, Python·Java·MySQL 같은 애플리케이션이 시작되지 않는 현상도 나타날 수 있습니다.
이런 오류가 발생하면 서버의 RAM이 모두 사용됐다고 생각하기 쉽습니다. 하지만 실제 물리 메모리가 부족한 경우뿐 아니라 Swap 부족, 프로세스의 가상 메모리 제한, 컨테이너 메모리 제한, 커널의 메모리 할당 정책 때문에도 문제가 발생할 수 있습니다.
특히 free -h에서 사용 가능한 메모리가 남아 있는데도
fork: Cannot allocate memory가 발생한다면
단순히 RAM 사용량만 확인해서는 원인을 찾기 어렵습니다.
이번 글에서는 메모리 상태 확인 → 프로세스별 사용량 분석 → OOM Killer 로그 점검 → Swap 및 시스템 제한 확인 → 원인별 해결 순서로 서버를 안전하게 점검하는 방법을 살펴봅니다.
Cannot Allocate Memory 핵심 명령어 한눈에 보기
오류가 발생했다면 먼저 아래 명령어로 시스템 메모리와 프로세스 상태를 확인합니다. 메모리가 심하게 부족한 서버에서는 새 명령어 실행 자체가 실패할 수 있으므로 가능하면 기존 SSH 세션이나 서버 콘솔을 유지한 상태에서 점검해야 합니다.
| 점검 목적 | 명령어 |
|---|---|
| RAM·Swap 사용량 | free -h |
| 메모리 상태 변화 | vmstat 1 5 |
| 메모리 사용 상위 프로세스 | ps aux --sort=-rss | head -n 15 |
| OOM 관련 커널 로그 | sudo journalctl -k -b | grep -Ei 'out of memory|oom|killed process' |
| 메모리 커밋 상태 | grep -E 'CommitLimit|Committed_AS' /proc/meminfo |
| 프로세스 자원 제한 | ulimit -a |
| Swap 장치 확인 | swapon --show |
가장 먼저 확인할 값은 단순한 free 메모리보다 실제로 새 작업에 사용할 수 있는 메모리를 추정하는 available 값입니다. 다만 available이 충분해 보여도 메모리 커밋 제한이나 cgroup 제한 등으로 할당에 실패할 수 있습니다.
1. Cannot Allocate Memory 오류가 발생하는 이유
리눅스에서 Cannot allocate memory는 일반적으로
ENOMEM 오류와 관련이 있습니다.
프로그램이 메모리 할당이나 프로세스 생성에 필요한 자원을 확보하지 못했을 때 나타날 수 있습니다.
예를 들어 새로운 프로세스를 실행하려 할 때 다음과 같은 메시지가 표시될 수 있습니다.
bash: fork: Cannot allocate memory
또는 Python 프로그램에서 메모리 할당이 실패하면 다음과 같은 오류가 발생할 수 있습니다.
MemoryError
두 오류 모두 메모리 자원 문제와 관련될 수 있지만 발생 위치와 직접적인 원인은 다를 수 있습니다.
대표적인 원인은 다음과 같습니다.
- 물리 메모리 부족: 실행 중인 프로세스가 사용 가능한 RAM을 대부분 소비한 경우
- Swap 부족: 메모리 압박 상황에서 추가적인 여유 공간이 부족한 경우
- 메모리 커밋 제한: 커널의 overcommit 정책에 따라 새로운 메모리 예약이 거부된 경우
- 프로세스 자원 제한: 주소 공간 크기 등 사용자 또는 프로세스별 제한에 도달한 경우
- 컨테이너 제한: Docker나 Kubernetes의 메모리 제한에 도달한 경우
- 커널 메모리 할당 문제: 특정 크기나 유형의 메모리 할당이 실패한 경우
- 애플리케이션 메모리 증가: 메모리 누수나 과도한 캐시 사용으로 사용량이 계속 늘어난 경우
따라서 메모리 부족 메시지가 나타났다고 해서 무조건 서버 RAM을 증설하거나 Swap부터 추가하는 것은 적절하지 않을 수 있습니다.
2. free -h로 RAM과 Swap 사용량 확인하기
가장 기본적인 점검은 free 명령어입니다.
free -h
다음은 설명을 위한 출력 예시입니다.
total used free shared buff/cache available
Mem: 7.7Gi 6.2Gi 210Mi 120Mi 1.3Gi 890Mi
Swap: 2.0Gi 1.7Gi 350Mi
여기서 중요한 항목은 다음과 같습니다.
- total: 전체 메모리 크기
- used: 사용 중인 메모리의 추정치
- free: 현재 사용되지 않는 메모리
- buff/cache: 버퍼와 파일 캐시 등으로 사용되는 메모리
- available: 새로운 작업에 사용할 수 있는 메모리의 추정치
리눅스는 남는 메모리를 파일 캐시 등에 활용하므로
free 값이 작다는 사실만으로 메모리가 부족하다고 판단하면 안 됩니다.
또한 Swap 사용량이 높다는 이유만으로 현재 메모리 부족 상태라고 단정할 수도 없습니다. Swap에 오래전에 이동된 페이지가 남아 있을 수 있기 때문입니다.
실제 메모리 압박 여부는 available 값과 함께 Swap 입출력, 프로세스 사용량, OOM 로그를 비교해야 합니다.
3. vmstat로 메모리 부족과 Swap 활동 확인하기
메모리 부족이 일시적인지 지속적인지 확인하려면
vmstat 명령어를 사용할 수 있습니다.
vmstat 1 5
이 명령어는 1초 간격으로 시스템 상태를 5회 출력합니다.
메모리 관련 항목에서는 swpd, free,
si, so 값을 확인합니다.
- swpd: 사용 중인 가상 메모리의 Swap 양
- si: Swap에서 메모리로 읽어 들이는 양
- so: 메모리에서 Swap으로 내보내는 양
- free: 사용하지 않는 메모리 양
si와 so 값이 반복적으로 높게 나타나고
서버 응답 속도도 느려진다면 메모리 압박으로 인해
Swap 입출력이 활발하게 발생하는 상황일 수 있습니다.
단, vmstat의 첫 번째 출력 행은 일반적으로
부팅 이후의 평균 통계를 포함하므로
실시간 상태를 분석할 때는 이후 출력 행도 함께 확인해야 합니다.
4. 메모리를 많이 사용하는 프로세스 찾기
메모리 사용량이 비정상적으로 높다면 어떤 프로세스가 메모리를 소비하고 있는지 확인해야 합니다.
ps aux --sort=-rss | head -n 15
위 명령어는 RSS 기준으로 메모리 사용량이 큰 프로세스를 확인하는 데 사용할 수 있습니다.
주요 항목은 다음과 같습니다.
- PID: 프로세스 식별 번호
- %MEM: 물리 메모리 대비 사용 비율
- VSZ: 프로세스의 가상 주소 공간 크기
- RSS: 실제 메모리에 상주하는 메모리 크기
- COMMAND: 실행 중인 프로그램
특히 특정 프로세스의 RSS가 계속 증가한다면 애플리케이션의 메모리 누수나 캐시 정책을 점검할 필요가 있습니다.
다만 RSS에는 공유 메모리도 포함될 수 있으므로 여러 프로세스의 RSS를 단순 합산하면 실제 물리 메모리 사용량과 차이가 날 수 있습니다.
원인이 확인되지 않은 상태에서 메모리 사용량이 높다는 이유만으로 프로세스를 강제 종료하면 데이터 손실이나 서비스 장애가 발생할 수 있습니다.
5. OOM Killer 로그 확인하기
리눅스 커널은 메모리 부족 상황에서 시스템을 보호하기 위해 OOM Killer를 통해 프로세스를 종료할 수 있습니다.
최근 부팅 이후의 커널 로그에서 관련 메시지를 검색합니다.
sudo journalctl -k -b | grep -Ei 'out of memory|oom|killed process'
OOM이 발생한 경우 다음과 비슷한 메시지가 기록될 수 있습니다.
Out of memory: Killed process 2481 (java)
total-vm:4194304kB, anon-rss:2097152kB
위 예시는 커널이 메모리 부족 상황에서 Java 프로세스를 종료한 경우를 나타냅니다.
다만 Cannot Allocate Memory 오류가 발생했다고 해서 반드시 OOM Killer가 실행되는 것은 아닙니다. 메모리 할당이 거부되더라도 프로세스 종료 없이 오류만 반환될 수 있습니다.
또한 OOM 로그가 없다고 해서 메모리 부족 문제가 없었다고 단정할 수 없습니다. 로그 보존 상태와 커널 설정, 컨테이너 환경에 따라 확인 가능한 정보가 달라질 수 있습니다.
6. RAM이 남아 있는데 Cannot Allocate Memory가 발생하는 이유
free -h에서 available 메모리가 충분해 보여도
새로운 메모리 할당이 실패할 수 있습니다.
대표적으로 커널의 메모리 커밋 정책을 확인해야 하는 경우가 있습니다.
cat /proc/sys/vm/overcommit_memory
이 값은 커널이 메모리 할당 요청을 어떻게 판단할지 결정하는 설정입니다.
- 0: 커널의 휴리스틱에 따라 메모리 커밋을 판단
- 1: 메모리 커밋을 폭넓게 허용
- 2: 설정된 커밋 한도에 따라 엄격하게 제한
현재 커밋 상태는 다음 명령어로 확인합니다.
grep -E 'CommitLimit|Committed_AS' /proc/meminfo
Committed_AS가 CommitLimit에 가까운 상황에서
엄격한 overcommit 정책이 적용되고 있다면
새로운 메모리 예약이 거부될 수 있습니다.
다만 문제를 해결하기 위해
vm.overcommit_memory=1로 무조건 변경하는 것은 권장하지 않습니다.
실제 메모리 부족 위험이 사라지는 것이 아니라
메모리 할당 실패 시점과 시스템 동작이 달라질 수 있기 때문입니다.
7. ulimit과 프로세스별 메모리 제한 확인하기
특정 사용자나 프로그램에서만 오류가 발생한다면 프로세스별 자원 제한을 확인할 필요가 있습니다.
ulimit -a
특히 다음 항목을 확인합니다.
- virtual memory: 프로세스의 가상 주소 공간 크기 제한
- data seg size: 데이터 세그먼트 크기 제한
- max user processes: 사용자에게 적용되는 프로세스 수 제한
프로세스 수 제한에 도달하면 일반적으로
Resource temporarily unavailable와 같은 다른 오류가 발생할 수 있으므로
메모리 할당 실패와 구분해야 합니다.
또한 systemd로 실행하는 서비스에는 셸의 ulimit과 별도로 자원 제한이 적용될 수 있습니다.
systemctl show myservice.service -p MemoryMax -p LimitAS -p LimitDATA
위 명령어의 myservice.service는
실제 서비스 이름으로 변경해야 합니다.
특정 서비스에서만 문제가 발생한다면 시스템 전체 메모리와 서비스별 제한을 함께 확인하는 것이 중요합니다.
8. Docker 컨테이너에서 메모리 부족이 발생하는 경우
Docker 컨테이너는 호스트 서버에 RAM이 충분히 남아 있어도 컨테이너에 설정된 메모리 제한에 도달할 수 있습니다.
실시간 컨테이너 메모리 사용량을 확인합니다.
docker stats --no-stream
특정 컨테이너의 메모리 제한과 OOM 종료 여부를 확인하려면 다음 명령어를 사용할 수 있습니다.
docker inspect mycontainer \
--format 'Memory={{.HostConfig.Memory}} OOMKilled={{.State.OOMKilled}}'
Memory 값은 바이트 단위이며,
0이면 Docker의 해당 메모리 제한이 설정되지 않았다는 의미입니다.
OOMKilled가 true라면 컨테이너가 OOM 상황으로 종료됐음을 나타낼 수 있습니다.
다만 현재 상태와 종료 이력에 따라 추가 로그 확인이 필요할 수 있습니다.
컨테이너의 메모리 제한을 높이기 전에 애플리케이션이 정상적으로 메모리를 사용하는지, 메모리 누수가 있는지 먼저 확인해야 합니다.
9. Swap 추가가 필요한 상황과 주의할 점
서버에 Swap이 없거나 메모리 압박이 반복된다면 Swap 구성을 검토할 수 있습니다.
swapon --show
free -h
Swap은 메모리 부족 상황에서 일부 페이지를 디스크로 이동할 수 있도록 지원하지만 RAM을 대체하는 고속 메모리는 아닙니다.
특히 디스크가 느리거나 메모리 부족이 지속되는 서버에서는 Swap 사용량 증가로 응답 지연이 심해질 수 있습니다.
또한 Swap을 추가한다고 해서 프로세스의 주소 공간 제한, 컨테이너 메모리 제한, 특정 메모리 할당 실패가 모두 해결되는 것은 아닙니다.
따라서 실제 메모리 압박이 확인됐을 때 워크로드와 저장장치 성능을 고려해 Swap 크기를 결정해야 합니다.
실전 점검 순서
리눅스 서버에서 Cannot Allocate Memory 오류가 반복된다면 다음 순서로 원인을 좁힐 수 있습니다.
# 1. 전체 RAM과 Swap 확인
free -h
# 2. 메모리와 Swap 활동 확인
vmstat 1 5
# 3. 메모리 사용량이 큰 프로세스 확인
ps aux --sort=-rss | head -n 15
# 4. OOM Killer 로그 검색
sudo journalctl -k -b | grep -Ei 'out of memory|oom|killed process'
# 5. Swap 장치 확인
swapon --show
# 6. 메모리 커밋 정책 확인
cat /proc/sys/vm/overcommit_memory
# 7. 커밋 사용량 확인
grep -E 'CommitLimit|Committed_AS' /proc/meminfo
# 8. 현재 셸의 자원 제한 확인
ulimit -a
Docker나 systemd 서비스에서만 문제가 발생한다면 해당 컨테이너 또는 서비스에 적용된 메모리 제한도 추가로 확인합니다.
메모리 사용량이 높은 프로세스를 발견했다면 서비스의 정상적인 사용 패턴인지, 특정 요청 이후 급격히 증가하는지, 재시작 이후에도 반복되는지 비교해야 합니다.
운영 서버에서는 원인을 확인하기 전에 캐시를 강제로 비우거나 프로세스를 무작정 종료하는 방법을 우선 사용하지 않는 것이 좋습니다.
정리
리눅스 서버에서 Cannot Allocate Memory 오류가 발생하는 이유는 단순한 RAM 부족만이 아닙니다. Swap 부족, 메모리 커밋 정책, 프로세스별 자원 제한, Docker 메모리 제한 등 여러 요인이 영향을 줄 수 있습니다.
먼저 free -h로 전체 메모리를 확인하고,
vmstat로 메모리 압박을 점검한 뒤,
프로세스 사용량과 OOM 로그를 함께 분석하는 것이 좋습니다.
특히 사용 가능한 RAM이 남아 있는데도 오류가 발생한다면 메모리 커밋 제한과 서비스·컨테이너별 메모리 제한을 확인해야 합니다.
핵심 점검 순서는 RAM·Swap 확인 → 메모리 사용 프로세스 분석 → OOM 로그 점검 → 시스템 제한 확인 → 원인에 맞는 설정 변경입니다.

