Notice
Recent Posts
Recent Comments
«   2024/04   »
1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30
Tags
more
Archives
Today
Total
관리 메뉴

INSPECT

메모리 누수(Memory Leak) 정리 본문

기타

메모리 누수(Memory Leak) 정리

INSPECT 2017. 2. 7. 20:44

어떻게 죽는가? 분석

C 소스 코드를 보면서 얘기하겠습니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
char* read_buffer(FILE *file, const int size)
{
  int foo = 0;
  char* buf = (char*) malloc(size);
 
    if (buf == NULL)
    {
      return NULL;
    }
    if (fread(buf, 1u, size, file) != size)
    {
      return NULL;
    }
    return buf;
}

함수 내에서 선언해서 사용하는 변수는 지역변수로 컴퓨터 구조의 스택이라는 자료구조 내에 보관됩니다. 위 코드 내의 정수형 foo가 이 경우에 해당되는데 이 변수를 지역변수라고 합니다. 지역 변수는 함수가 종료될 때, 자동으로 사라집니다. 문제가 되는 것은 buf 변수입니다. 이 변수는 malloc 함수를 통해서 힙(Heap) 영역의 메모리를 할당받아서 사용하는데, 이 힙 영역의 메모리를 할당 받으면 명시적으로 메모리 해제를 해줘야 합니다. 하지만 fread 함수를 통해서 파일 읽기가 실패하면 11번 째 줄에서 NULL을 리턴하고 함수가 종료되는데요, 바로 여기서 메모리 누수가 발생합니다. 힙 영역의 메모리를 할당 받은 buf 변수가 free를 통해서 해제되지 않았기 때문입니다. 이 경우 프로그램이 종료되어도 해당 메모리 공간을 다시 사용할 수가 없으며, 이런 메모리 누수가 누적되면 결국 시스템 전체의 메모리 부족 현상이 발생할 수 있습니다.

아래와 같은 경우도 생깁니다.

1
2
3
char *foo = (char *) malloc(100);
char *bar = (char *) malloc(200);
bar = foo;

이 경우는 bar 포인터 변수가 힙 영역에 할당된 메모리 200바이트를 가리키고 있는데, bar의 주소 값에 foo의 주소 값을 대입하게 되면 이전에 bar 변수를 통해 할당한 힙 영역의 메모리 200바이트에 접근할 방법이 사라집니다. 이 경우에도 메모리 누수가 생깁니다.

1
2
3
4
5
6
7
8
9
typedef struct _my_struct {
char *foo;
int bar;
} my_struct;
 
my_struct *entity = (my_struct *)malloc(sizeof(my_struct));
entity->foo = (char *)malloc(100);
 
free(entity);

이 경우에는 구조체 my_struct의 필드인 foo가 힙 메모리 영역을 100바이트 할당 받았으나, 그 부모인 entity 가 먼저 해제되어서 foo에 접근해서 해제할 방법이 없어진 경우입니다. 이 코드를 실행하면 100바이트의 메모리 누수가 발생합니다.

1
2
3
4
5
6
7
8
9
char* get_buffer(void)
{
  return (char *)malloc(100);
}
 
void test_func()
{
  get_buffer();
}

위 코드의 경우 get_buffer() 함수가 힙 메모리에서 100바이트를 할당해서 그 포인터를 반환하지만 test_func() 함수에서는 이를 받는 변수가 없습니다. 이 경우에도 힙 메모리에 할당된 100바이트에 접근할 방법이 사라지기 때문에 메모리 누수가 발생합니다.

찾기 힘들다

위의 코드는 메모리 누수가 어떻게 일어나는지를 한 눈에 볼 수 있도록 단순화 시켜서 메모리 누수 원인을 빠른 시간 안에 정확하게 찾을 수 있습니다. 하지만 일반적으로 방대한 소스코드로 개발된 복잡한 프로그램에서 메모리 누수를 찾기란 매우 어렵습니다. 시스템 자원을 감시하거나 메모리 할당 실패 시 별도의 로그를 기록하지 않으면 특히 더 찾기 어렵습니다. 오류를 재현하기도 힘들 뿐더러 불규칙적인 시간과 증상을 보이면서 시스템이 장애를 일으키기 때문에 원인이 정확하게 무엇인지 추정할 수 없게 만듭니다.?메모리 누수는 프로그램뿐만 아니라 전체 시스템에 영향을 주기 때문에 해당 컴퓨터에서 작동 중인 모든 소프트웨어를 다 검사해야 하기도 합니다.

자바, 안드로이드, Objective-C 에도 존재

예제로 C 언어로 된 코드를 사용했지만 메모리 누수는 비단 C와 C++에만 존재하는 것이 아닙니다. 동적으로 할당한 메모리 중 필요 없게 된 영역을 해제하는 가비지 콜렉터(Garbage Collector) 기법을 이용하는 자바와 안드로이드에도 엄연히 메모리 누수가 존재합니다. 다만 앞서 소개한 C/C++ 코드에서 같이 할당한 힙 영역을 접근할 수 있는 포인터가 사라지는 경우에는 자바의 가비지 콜렉터가 동작해서 할당한 힙 영역을 다시 사용할 수 있게 해줍니다. 자바의 메모리 누수가 문제가 되는 경우는 Loitering Object 입니다. Loitering 의 뜻은??’어슬렁거리다, 서성이다’ 라는 뜻인데요, 아래의 코드에서 나타날 수 있습니다.

1
2
3
4
ArrayList array = new ArrayList();
SomeObject obj = new SomeObject();
array.add(obj);
.... // something to work

이 코드는 ArrayList형 변수 array에 SomeObject라는 객체를 추가했으나, 작업 후 array 내부의 객체를 제거하지 않음으로서 메모리 누수가 발생하는 코드입니다. ?이 경우 obj는?Loitering Object가 되서 obj가 할당한 메모리가 시스템으로 반환되지 않고 계속 메모리를 점유하게 됩니다.

보안도 위협

이 메모리 누수는 대부분의 경우 시스템을 전반적으로 불안정하게 만들지만, 때에 따라서는 보안에도 큰 위협이 될 수 있습니다. 메모리 누수가 있는 프로그램을 공격하여 시스템을 중단시키거나, 임의의 코드를 실행할 수 있으며, 메모리 부족 조건 하에서 발생하는 예기치 못한 동작을 이용해서 시스템을 공격할 수도 있습니다.

메모리 누수 탐지 방법

Java와 같은 언어에서는 메모리 누수를 탐지하는 도구가 있고 C/C++의 경우 프레임워크에서 지원하는 라이브러리가 있습니다. 윈도우즈의 CRT 라이브러리가 그 예가 되겠죠. 유명한 정적 코드 분석도구에서도 메모리 누수를 탐지하는 기능을 제공합니다.


원문 :  http://story.wisedog.net/%EB%A9%94%EB%AA%A8%EB%A6%AC-%EB%88%84%EC%88%98-memory-leak%EB%9E%80/

'기타' 카테고리의 다른 글

Spydealer  (0) 2017.08.07
[unescape]  (0) 2017.03.04
브라우저는 어떻게 동작하는가  (0) 2017.02.11
[SIEM & ESM] SIEM과 ESM비교  (0) 2017.02.07
[MySQL] root 비밀번호 변경하기  (0) 2017.01.30
Comments