mir.pe (일반/밝은 화면)
최근 수정 시각 : 2024-12-06 15:04:26

메모리 누수

램 누수에서 넘어옴
1. 개요2. 상세3. 예시

1. 개요

메모리 누수(Memory leak)는 응용 프로그램에서 데이터를 메모리에 올렸다가, 이것이 쓸모없어지는 시점에서 적절하게 제거되지 않는 것을 ' 누수'에 빗댄 말이다. 영어를 그대로 읽은 '메모리 릭'이라는 표현으로도 적지 않게 쓰인다.

2. 상세

메모리 누수가 지속되면 메모리 자원의 반환이 원활히 되지 않아 메모리 부족으로 이런저런 버그가 생기거나, 운영체제가 전반적으로 느려지고[1], 더 나아가 프로그램이 응답하지 않거나 아예 강제로 종료된다.[2][3] 쓰레기 수집 기능은 이를 방지하기 위한 기능이지만 완전하지는 않다[4]. 발적화의 원흉 중 하나.

메모리에 데이터가 남아 있어도 그 상황을 운영체제가 통제하고 있다면 데이터 누수라고 하긴 어렵다. Windows Vista 이후의 운영체제 및 안드로이드에선 옛날만큼 메모리 공간이 빡빡하지 않다는 것을 감안하여 사용자가 종료시킨 프로그램을 일부러 메모리 상에 남겨두어 나중에 사용자가 다시 찾았을 때 더 빠르게 응답할 수 있도록 설정되어 있다. 여기서 한술 더 떠서 자주 사용하는 프로그램이라면 부팅 이후로 아직 실행된 적이 없더라도, 운영체제가 먼저 메모리에 띄워놓기까지 한다.[5] 하지만 이런 경우들은 운영체제가 현재 상황을 알면서 일부러 놔둔 것이므로 사용자가 다른 작업을 하느라 메모리 공간이 부족해지면 운영체제가 알아서 메모리를 정리해준다.[6] 다만 윈도우 10 1703부터는 저 정리의 반응속도가 느려서 고사양 게임에서 마이크로스터터링을 일으키는 문제가 있었다.[7] 게임 자체 최적화 문제와 맞물려서 큰 논란이 된 가장 대표적인 사례가 바로 PUBG ( 톰 클랜시의 디비전 2의 사례를 포함한 설명 #) 그리고 윈도 모바일은 메모리가 빡빡한데도 기본 설정으론 이렇게 동작해서 문제였다.[8]

한편 FORTRAN이나 BASIC, C 등의 프로그래밍 언어는 쓰레기 수집을 지원하지 않는다. 애초에 이 언어들은 프로그래머를 믿고 컴파일러의 개입을 최소화하는 게 특징이다. 특히 C/C++은 포인터와 동적 할당이 기본 테크닉이라 더 심하다. C++의 경우, C++11 이후 추가된 스마트 포인터에서 참조 횟수 카운팅 쓰레기 수집을 지원하지만, 어디까지나 선택사항이고 성능 하락을 막기 위해 직접 관리해야 하는 부분도 적지 않다. 이에 따라 FORTRAN, BASIC, C, C++ 전공의 프로그래머는 오늘도 메모리와의 전쟁을 치르고 있다.

가상 메모리 개념을 사용하는 운영체제의 프로세스가 런타임 환경에서 생긴 누수는 프로세스가 종료되면서 모두 해제된다.
이는 유저랜드에서만 해당될 뿐 드라이버와 같은 커널 모드에서 동작하는 코드의 누수는 운영체제를 재시동하지 않는 이상 해결할 수 없다.

3. 예시

#!syntax cpp
#include <stdlib.h> // malloc(), free()

int main()
{
  static const int DEFSIZE  = 4;
  char           **strTable = (char **)malloc(sizeof(char *) * DEFSIZE); // Figure 1
  for ( int i = 0; i < DEFSIZE; ++i )
  {
    strTable[i] = (char *)malloc(1024); // Figure 2
  }

  free(strTable); // Figure 3
  strTable = NULL;
}


strTable에 4개의 포인터를 할당하고 (Fig 1), 할당된 포인터에 각 1024바이트의 메모리를 추가로 할당하였다. (Fig 2)
이후 strTable을 할당 해제해서 (64비트 기준) 32바이트가 해제되었지만 내부에서 할당한 4개의 1024바이트 블록은 해제되지 않았고 더 이상 접근할 수 없게 되어 결과적으로 위 프로그램은 총 4096 바이트의 누수가 발생한다. (Fig 3)


[1] 메모리가 부족해질수록 운영체제는 메모리 압축 그리고 디스크 스왑을 시도해보기 때문이다. [2] 일반적으로는 메모리가 계속 불어나다가 멈추지만 가끔 램 여유가 충분히 된다면 한계까지 잡아먹는 버그로 유명한 프로그램들도 있었다. [3] 32비트 윈도우에선 프로그램당 최대 점유할 수 있는 메모리가 2G라 메모리 누수가 발생할 경우 64비트보다 빨리 터진다. [4] Java/ C#에서 간단한 예시로, 만약 개발자가 자원을 static에 올려두고 해제하지 않는다면 쓰레기 수집기와 상관없이 메모리 누수가 발생한다. [5] 이러한 메커니즘을 윈도우에선 superfetch, 리눅스에선 readahead라고 부른다. 하지만 메모리에 데이터를 미리 올리기 위해 때론 렉을 유발하기도 한다. 윈도우에서 아무 작업도 안 하고 있는데 저장장치 혼자 바쁘다면 superfetch 때문인 경우가 많다. [6] 그래서 최근 실행 목록에서 모두닫기를 누르지 말라고 하는 이유다. [7] https://quasarzone.com/bbs/qb_tip/views/12664 [8] 사실 초기 Android도 메모리를 한번씩 정리해줘야 했다.

파일:CC-white.svg 이 문서의 내용 중 전체 또는 일부는
문서의 r45
, 1.2번 문단
에서 가져왔습니다. 이전 역사 보러 가기
파일:CC-white.svg 이 문서의 내용 중 전체 또는 일부는 다른 문서에서 가져왔습니다.
[ 펼치기 · 접기 ]
문서의 r45 ( 이전 역사)
문서의 r ( 이전 역사)