오늘 하루에 집중하자
  • [CS] 동적 메모리 할당(Dynamic Memory Allocation), 프로세스 메모리 구조, 메모리 누수(Memory Leak)
    2022년 12월 01일 20시 50분 08초에 업로드 된 글입니다.
    작성자: nickhealthy

    동적 메모리 할당(Dynamic Memory Allocation)이란?


    동적 메모리 할당(DYNAMIC MEMORY ALLOCATION) 은 컴퓨터 프로그래밍에서 실행 시간 동안 사용할 메모리 공간을 할당하는 것을 말한다. 즉, 프로그램이 실행되는 동안(runtime) 입력되는 데이터에 맞게 기억 공간을 확보하는 것을 동적 메모리 할당이라고 한다. 이는 프로그램이 실행하는 순간 프로그램이 사용할 메모리 크기를 고려하여 메모리의 할당이 이루어지는 정적 메모리 할당과 대조적이다.

     

    그럼 정적 메모리 할당은 무엇일까? 정적 메모리 할당(STATIC MEMORY ALLOCATION)은 프로그램을 컴파일하는 단계에서 필요한 기억 공간의 크기를 결정하는 것이다. 즉, 프로그램을 작성한 이후 컴파일러는 "이 프로그램이 몇 바이트가 필요하겠구나"라는 결정을 이미 다 끝낼 수 있어야 하는 것이다. 따라서 아래와 같은 코드는 에러가 난다.

     

    #include<stdio.h>
    // #define num 20
    
    int main() {
        int num;
        scanf("%d", &num);
        int score[num];
    }

     

    위와 같이 배열을 선언하게 되면 num 입력 값을 사용자로부터 받고, score에 배열의 크기가 지정될 것 같지만 그렇지않다. 위에서 설명한 이유와 같은 맥락인데, 컴파일 단계에서 정적 메모리 할당과 같은 방법은 해당 프로그램에서 얼마만큼의 메모리가 필요한지를 명시해줘야 하는데, 사용자 입력은 컴파일 단계 이후부터 이루어지므로 컴파일러는 컴파일 할 때 score 배열이 얼마만큼의 공간이 필요한지를 모르기 때문이다. 마찬가지로 위의 define 으로 정수형 상수 값을 num에 저장시켜놨는데 해당 주석을 풀고, main 함수 안에 있는 num 변수, scanf 함수 라인을 주석처리한다면 컴파일러는 비로서 컴파일 단계에서 얼마만큼의 메모리가 필요한지를 인지하고 메모리를 할당해주게 된다.

     

    동적 메모리를 왜 쓰는가?

    그럼 동적, 정적 메모리가 어떤 개념인지는 알겠는데 그럼 왜 쓰는가?

    • 한정적인 메모리 자원을 효율적으로 사용하기 위해
      • 입력 받는 크기가 매번 달라서 공간이 부족하거나, 공간을 낭비할 수 있는 경우를 동적 할당 방식을 통해 방지할 수 있다.(아래 그림 참고)
    • 함수 리턴 이후에도 메모리 할당이 살아있게 하고 싶을 때(메모리 구조에서 heap 영역)
      • 일반 변수나, 함수의 경우 stack 이라는 메모리 공간에 할당되는데, stack 영역의 경우 실행 이후 메모리를 반환하기 때문에 메모리를 반환하고 싶지 않다면 동적 할당을 이용해야 한다.

     

     

    프로세스 메모리 구조

    동적 할당은 메모리와 관련되어 있기 때문에 메모리 구조에 대해 알고 있어야한다.

    • 코드 영역(code segment) - 실행파일(바이너리) 코드가 저장됨
      • 프로그램이 실행될 때 메모리에 할당된다.
    • 데이터 영역(data segment) - 전역변수나 static 변수가 저장됨(실행파일에 존재함)
      • 프로그램이 실행될 때 메모리에 할당된다.
      • 전역변수 또는 static data들은 프로그램이 실행될 때 항상 메모리 공간을 가지고 있어야 한다. 그래야 함수가 어느 곳에서도 접근 할 수 있고 static 변수 같은 경우에 함수를 실행/종료하여도 값을 유지할 수 있다.
    • 힙 영역(heap) - 프로세스가 돌아가는 런타임에 크기를 알려줌으로써 영역을 확보하는 공간
      • 프로그램 런타임에 메모리 동적할당 시 힙 영역에 저장된다. 힙은 주로 원시 자료형(primitive data type)이 아닌 보다 큰 크기의 데이터를 담고자 동적으로 할당하는 메모리 공간
      • heap 메모리는 유저가(응용 프로그램) 직접 관리한다. 메모리를 할당하고 직접 해제하기 전까지의 책임은 응용프로그램에게 있다. 즉, C언어의 경우 malloc 라이브러리 함수로 할당하고, free로 반환한다.
    • 스택 영역(stack) - 컴파일 타임에 지역변수나 매개변수가 차지하는 공간이며, scope가 끝나는 지점에서 메모리를 반환한
      • 함수가 대표적인 예

     

    프로세스 메모리 구조

     

    동적 할당 사용법(c언어 malloc)

    //헤더파일 생략
    int main()
    {
        // 1-1. malloc 사용해 동적할당
        int* pnum1 = (int*)malloc(sizeof(int));
        // 1-2. 메모리 해제
        free(pnum1);
        
        return 0;
    }

    malloc은 메모리 할당에 성공하면 heap에 가서 요청한 크기만큼 공간을 잡은 뒤 메모리의 시작 주소값을 리턴해준다. malloc은 리턴하는 메모리를 초기화하지 않으며, void* 타입으로 리턴해주기 때문에 형변환을 반드시 진행해주어야 한다. 만약 malloc이 메모리 할당에 실패하였다면(예: 프로그램의 가상메모리 보다 더 큰 크기의 메모리를 요청할 경우) NULL을 반환한다.

     

    또한 위의 코드에서 선언한 포인터 변수 *pnum은 지역변수이기 때문에 stack에 할당되게 되고,

    포인터 변수가 가리키고 있는 곳은 malloc으로 리턴받은 heap에 생성된 메모리 주소이다.

    동적 할당 메모리 주소

     

    메모리 해제하기(명시적 할당기 vs 묵시적 할당기)


    명시적 할당기 - 명시적으로 메모리 블록을 할당하고(malloc), 명시적으로 블록을 해제해야 함(free)

    • C언어의 malloc 패키지가 명시적 할당기에 해당한다.
    • 메모리를 할당하고, 해제하기 전까지는 메모리 공간이 계속 유지하게 된다.

    묵시적 할당기 - 명시적으로 블록을 할당하고, 별도로 블록을 해제하지는 않는다. 대신 할당기는 사용되지 않는 할당된 블록을 자동으로 탐지해서 해제해준다.

    • JAVA와 같은 프로그래밍 언어에서는 묵시적 할당기에(가비지 컬렉터, garbage collector) 해당한다.

     

    메모리 누수(memory leak)

    메모리 누수란 필요하지 않은 메모리를 계속해서 점유하고 있는 현상을 말한다.

    메모리 할당과 관리를 사용자가 직접 관리하는 C언어의 특성상 메모리 누수 문제가 자주 발생하며, 에러찾기가 쉽지 않다고 한다. 컴파일 단계에서 메모리 누수가 발견되어도 컴파일은 잘 된다. 

     

    #include<stdio.h>
    #include<stdlib.h>
    
    int main() {
        int *p1 = (int *)malloc(sizeof(int));
        printf("p1 memory %p\n", p1);
        
        p1 = (int *)malloc(sizeof(int));
        printf("p1 memory %p\n", p1);
        free(p1);
    }

    위와 같이 코드를 작성하였을 때, 처음 할당받은 heap 메모리 위치를 p1으로 접근했는데, p1에 다른 값을 대입하면 처음 heap 메모리 위치에 접근할 방법을 유실하기 때문에 메모리를 해제할 방법이 없고, 메모리 누수가 발생하게 된다. 아래 이미지는 메모리 누수가 발생한 것을 캡처한 것이다.

     

    메모리 누수가 발생한 모습

     

    동적 메모리 할당의 장점과 단점

    • 장점: 상황에 따라 원하는 크기만큼의 메모리가 할당되므로 경제적이며, 이미 할당된 메모리라도 언제든지 크기를 조절할 수 있다.
    • 단점: 더 이상 사용하지 않을 때 명시적으로 메모리를 해제해 주어야 한다.

     


    Ref

    Process Address Space 메모리내 프로세스 구조

    동적할당 언제 사용하나요? 동적할당이 뭔가요?

    동적 메모리 할당이란?

     

    댓글