메모리 누수(Leak)가 발생했을 때 시스템은 어떻게 반응할까?
How does a system react when a memory leak occurs?
Nov 22, 2025
Memory Leak 발생하면…?1. Memory Leak이 발생한 프로그램2. 실행 중인 다른 App3. System (OS)Memory 누수 시, 시스템은 어떻게 동작할까?1. 메모리 누수 발생2. Overcommit3. Anonymous Page4. Slab그래서?1. 시간에 따라 보면2. 메모리 누수 패턴으로 보면3. 결론
일반적으로 사람들은 Memory Leak에 대해서 상당히 경계합니다. 시스템의 Memory Leak이 발생하고 실제 시스템의 가용 메모리가 부족해지면 어떤 일이 발생할까요?
그리고 실제 메모리 누수가 발생하면 시스템은 어떻게 대응할까요? 각 메모리 지표들은 어떤 패턴을 보이게 될까요? 실제 메모리 누수를 재현을 통해 확인해 보겠습니다.
Memory Leak 발생하면…?
1. Memory Leak이 발생한 프로그램
- 성능 저하가 발생합니다. 프로그램이 메모리를 계속 할당하면서 가비지 컬렉션이나 메모리 관리 오버헤드가 증가하여 처리 속도가 느려집니다.
- 응답 시간(Latency)이 증가 합니다. 메모리 부족으로 인해 디스크의 가상 메모리를 사용하는 빈도가 높아지고, 이는 곧 I/O 작업으로 이어지고 프로그램의 응답 시간이 증가하게 됩니다.
- 프로그램이 강제 종료 될 수도 있습니다(OOM). 할당할 메모리가 운영체제에 완전히 고갈되면, 해당 프로그램은
Out of Memory (OOM)오류를 만나 시스템에 의해 강제 종료되거나Segmentation Fault와 같은 치명적인 오류로 인해 중단됩니다.
- 다른 Application이 사용 할 자원이 부족해 집니다. 누수된 메모리가 계속 점유되어 다른 프로그램이 사용할 수 있는 메모리가 줄어들게 됩니다.
2. 실행 중인 다른 App
- 마찬가지로 성능 저하가 발생합니다. 메모리 부족 상황에서는 운영체제가 메모리를 확보하기 위해 다른 애플리케이션의 메모리를 디스크의 스왑을 더 자주 수행합니다. 이 과정에서 다른 앱들도 I/O 지연을 겪으며 전반적인 성능이 떨어지게 됩니다.
- 리소스 경합 (Resource Contention)이 발생합니다. 제한된 메모리를 두고 Leak 프로그램과 다른 앱들이 경합을 벌이게 되어 처리 속도가 불안정해집니다.
- OOM Kill 위험이 증가합니다. Leak 프로그램이 메모리를 독점하다가 갑자기 OOM Kill로 종료되지 않고 지속적으로 메모리를 소모하는 경우, 다른 애플리케이션이 메모리 할당 요청 시 거부되거나, 심지어는 OOM Killer가 Leak 프로그램 대신 상대적으로 덜 중요한 다른 앱을 종료시킬 수도 있습니다.
3. System (OS)
메모리 누수가 임계점을 넘어 시스템 전체의 가용 메모리를 고갈시키면 시스템 전반적인 안정성에 문제가 생깁니다.
- 시스템 불안정 및 멈춤 (Freeze) 현상이 발생합니다. 스왑이 과도하게 발생하면 시스템이 실제 메모리보다 훨씬 느린 디스크 I/O에 의존하게 됩니다. 이를 스래싱(Thrashing)이라고 하며, 이 상태가 되면 시스템은 거의 모든 시간을 메모리 페이지 교환에 소모하게 되어 사용자 입력에 거의 응답하지 않는 상태(먹통)가 될 수 있습니다.
- 커널 패닉 또는 재부팅이 발생할 수도 있습니다. 극심한 메모리 부족으로 운영체제 커널 자체에 필요한 자원까지 부족해지면, 커널이 정상적인 작동을 멈추고 커널 패닉(Kernel Panic)을 일으키거나 시스템이 자동으로 재부팅될 수 있습니다.
- 새로운 프로세스 생성이나 연결을 거부할 수도 있습니다. 서버 환경에서는 메모리 부족으로 인해 새로운 프로세스 생성이나 네트워크 연결과 같은 기본적인 운영체제 서비스 요청까지 실패하여 서비스 중단이 발생할 수 있습니다.
Memory 누수 시, 시스템은 어떻게 동작할까?
먼저 실험 환경은 아래와 같습니다.
- OS : Ubuntu 20.04 LTS
- RAM : 32 GB
- Monitoring : Node-Exporter + Prometheus + Grafana
- Duration : 10시간 정도?
그라파나 대시보드는 다음과 같은 지표를 측정하고 있습니다.
- Memory Committed (커밋된 메모리)
- Anonymous Pages (프로세스 할당 메모리)
- Memory Slab (커널 캐시)
- LRU Active/Inactive (페이지 캐시 상태)
- Memory Writeback and Dirty (디스크 쓰기 대기)
1. 메모리 누수 발생
메모리 누수를 발생시키기 위해 stress-ng와 일부 python 스크립트 등 몇 가지 도구를 이용했습니다.
sudo apt install stress-ng
stress-ng --vm 1 --vm-bytes 5G --vm-keep --timeout 0--vm-keep 옵션이 핵심입니다. 이 옵션은 할당한 메모리를 해제하지 않고 계속 유지하도록 하여 실제 메모리 누수와 동일한 상황을 만들어냅니다.그리고 약 10시간 동안 시스템을 관찰해보겠습니다.

약 10시간 동안 시스템의 Memory 사용률은 20% 이하에서 99% 넘게 상승했습니다. 현재 상태에서 시스템의 대부분 App은 초살 직전의 상태입니다.
2. Overcommit
그리고 Committed Memory가 인상적인데,

- Committed_AS: 74.7 GiB ← 프로세스들이 "약속받은" 메모리
- CommitLimit: 17.6 GiB ← 시스템이 실제 제공 가능한 최대치
Linux는 요구된 메모리를 그대로 할당하는게 아니라 필요한 시점에 필요한 만큼의 메모리를 할당합니다.대부분의 프로그램은
malloc() 등으로 메모리를 할당받더라도, 할당받은 메모리 전체를 실제로 사용(접근)하지 않는 경우가 많습니다. 요구 메모리의 총합이 OS가 할당할 수 있는 값보다 많아도 실제로는 메모리가 부족해지기 전까지 사용되지 않을 가능성이 있기 때문에 프로그램의 메모리 할당 요청에 대해서 OK 사인을 보냅니다. 그래서 실제 메모리 할당이 프로그램이 할당받은 영역에 이루어지는 건 I/O와 같은 접근이 이루어질 때 페이지 단위로 발 생하게 됩니다.
malloc()은 주소 공간만 확보해주는 것이고 실제로 물리적인 공간은 필요한 시점에 필요한 만큼만 할당하게 됩니다. 그러니까, 실제로는 안쓸 수도 있고 그냥 메모리 요청하면 그래~ 그정도 까지는 할당해줄게 여유 있으면~ 하고 최대 할당치가 허용된 겁니다.
참고로 현재 Memory Over Commit 비율은 무려 481%입니다.
시스템의
vm.overcommit_memory와 vm.overcommit_ratio 같은 overcommit 값들은 메모리 할당 요청을 시스템(OS)가 수락할지 거부할지 결정하는 조건을 의미합니다. 안정성 확보와 OOM-Killer 회피의 목적으로 실제로는 100% 이상의 메모리 할당을 허용하게 되는데 일반적으로는 100% ~ 200% 정도 사이로 잡습니다. 그리고 여기서부터가 핵심인데, 메모리 지표는 어떤 패턴을 보였을까요?
3. Anonymous Page

Anonymous Pages는 파일로 백업되지 않은 프로세스의 순수 메모리를 의미합니다. 힙(heap), 스택(stack) 등이 여기 포함됩니다.
- 시작: 2.75 GiB
- 종료: 29.8 GiB
- 증가: 약 10배
이 그래프의 핵심은 일방적인 증가입니다. 정상적인 상태라면 메모리를 할당하고 해제하면서 증가와 감소를 반복하거나 일정하게 유지됩니다. 하지만 이 경우는 해제 없이 계속 증가만 하고 있습니다. 이것이 바로 메모리 누수의 일반적인 패턴입니다.

LRU (Least Recently Used) 메커니즘은 Linux 커널이 메모리를 관리하는 알고리즘입니다.
그리고 Memory LRU Active/Inactive 그래프를 보면,
- Active: 최근에 사용된 페이지
- Inactive: 오래 사용되지 않은 페이지 (회수 후보)
관찰결과, 누수가 시작된 16:00 이전에는 Inactive가 ~24 GiB로 안정된 상태이나 16:00 이후에는 Inactive가 점점 줄어들게 됩니다. 이는 메모리 누수를 의심할 수 있는 일반적인 상황으로,
Anonymous Page는 Application에서 메모리를 할당받고 사용 후 해제하지 않으면, 이 메모리는 Anonymous Page로 남아 시스템 메모리를 계속 점유하게 됩니다. 시스템은 메모리 부족 상황에 대응하기 위해, Inactive Page를 회수하게 됩니다.
Inactive Page ?
언제든지 회수하여 다른 용도로 사용할 수 있는 캐시 메모리로서, 회수가 용이합니다.
- 클린 페이지 (Clean Page): 디스크에 저장된 내용과 동일한 내용(수정되지 않음)을 담고 있는 Inactive Page는 단순히 메모리에서 해제됩니다. 데이터는 이미 디스크에 있으므로, 나중에 다시 필요하면 디스크에서 읽어 오기만 하면 됩니다.
- 더티 페이지 (Dirty Page): Inactive Page 중에서 파일 내용이 수정되었지만 아직 디스크에 기록되지 않은 페이지(더티 페이지)는 회수 전에 디스크에 쓰기 작업(Writeback)을 완료해야 합니다. 이 작업이 끝나면 클린 페이지가 되어 메모리에서 해제됩니다.
하지만 위 패널을 보면 Inactive Page를 계속 회수해서 메모리를 확보하는데도, Anonymous Page는 계속 늘어 시스템이 사용할 수 있는 가용 메모리가 점점 줄어들게 됩니다. Anonymous Page는 프로세스가 실제로 사용 중인 메모리로서 디스크로 스왑하지 않는 한 회수가 불가능합니다.
4. Slab

Slab은 커널이 자주 사용하는 객체들(inode, dentry 등)을 미리 할당해두는 캐시입니다.
- SReclaimable : 필요시 회수 가능한 캐시
- SUnreclaim : 회수 불가능한 커널 메모리
회수 불가능한 SUnreclaim를 제외하고 SReclaimable 그래프가 아래로 수직하락 하고 있는데, 이는 커널이 자신의 성능을 위해 들고 있던 캐시마저 포기하고 있다는 의미로 생각할 수 있습니다.
이는 메모리 상황이 정말 심각한 상태임을 의미하는데, 말그대로 메모리 영끌하고 있는 모습을 볼 수 있습니다.
그래서?
메모리 부족시 시스템의 메모리 상황이 어떻게 변하는지 대략적으로 알 수 있었습니다.
1. 시간에 따라 보면
- 캐시를 회수합니다. ( 16:00 ~ 17:00 )
- Page Cache 회수
- LRU Inactive 감소
- 적극적으로 회수합니다. ( 17:00 ~ 18:00 )
- Slab의 캐시 포기
- 결국 누수되는 메모리를 스왑 등으로 해결하지 못하고 죽음을 기다립니다.(OOM Killer) (18시 이후 ~ 누수 상황 해결 전까지)
- Overcommit 481%
- 회수 가능 메모리 고갈
- OOM Killer 직전상태에 도달
2. 메모리 누수 패턴으로 보면
- Anonymous Pages의 일방적 증가
- 정상 프로그램은 할당과 해제를 반복하지만
- 누수 프로그램은 해제가 없습니다.
- 시스템 대응이 무력합니다.
- LRU Inactive 감소 → 효과가 없습니다.
- Slab 축소 → 효과가 없습니다.
- Anonymous는 계속 증가
- 대체로 일정한 증가율을 보입니다.


프로세스를 종료하자 메모리가 즉시 정상으로 돌아왔습니다. 이것은 메모리 누수의 또 다른 특징입니다. 프로세스가 종료되면 OS가 모든 메모리를 회수합니다.
3. 결론
시스템 자원에 대한 모니터링은 조기 감지가 참으로 중요합니다. 특정 사용률을 넘어가면 알람을 보낸다던가.. 데몬으로 상황을 감지하고 종료시켜준다던가 하는…
그리고 시스템은 무력했지만 생각보다 오래 버텨줬습니다. 481% 오버커밋상태에도 Crash하지 않고 정교하게 메모리를 관리하며 OOM Killer를 막았습니다.
또.. 메트릭을 수집하고 관찰할 수 있는 환경을 마련해야 하는 건 언제나 필요한 일입니다. free -h 같은 걸로는 정교한 추세와 패턴을 알기 어렵습니다.
>>> 운영환경이라면 모니터링 깔고, 알람 깔자
Share article