Programming/C

C언어 - 메모리 관리와 메모리의 동적 할당

JunsuKim 2021. 10. 18.
728x90

메모리의 구성

프로그램을 실행했을 때 운영체제에 의해 마련되는 메모리의 구조는 4개의 영역으로 나뉜다.

메모리 공간을 나눠놓은 이유는 유사한 성향의 데이터를 묶어 저장하면, 관리가 용이해지고 메모리의 접근 속도가 향상되기 때문이다.

메모리 영역별로 저장되는 데이터 유형

각 영역 별 특성에 대해 알아보면 다음과 같다.

1. 코드 영역

코드 영역에는 이름 그대로 실행할 프로그램의 코드가 저장되는 메모리 공간이다.

CPU는 코드 영역에 저장된 명령문을 하나씩 가져가 실행을 한다.

 

2. 데이터 영역

데이터 영역에는 전역변수와 static으로 선언되는 static 변수가 할당된다.

이는 프로그램의 시작과 동시에 메모리 공간에 할당되어 프로그램이 종료될 때까지 남아있다는 특징이 있다.

 

3. 스택 영역

스택 영역에는 지역변수와 매개변수가 할당된다.

따라서 이 영역에 할당된 변수들은 선언된 함수를 벗어나면 소멸된다는 특징이 있다.

 

4. 힙 영역

데이터 영역과 스택 영역에 할당되는 변수들은 이미 생성과 소멸의 시점이 결정돼있다.

힙 영역에서는 이들과 달리 프로그래머가 원하는 시점에 변수를 할당하고 소멸하도록 지원을 한다.

malloc, free 함수

이 두 함수는 힙 영역의 메모리 공간 할당과 해제의 역할을 한다.

#include<stdio.h>
void *malloc(size_t size);
void free(void *ptr);

malloc 함수를 이용해 메모리 공간을 할당하고, 할당된 메모리 공간은 free 함수의 호출을 통해 해제한다.

malloc 함수 호출로 할당된 메모리 공간은 free 함수의 호출을 통해 해제하지 않으면 계속 남아있게 되어

힙 영역을 "프로그래머가 관리하는 메모리 공간"이라 한다.

malloc 함수는 주소 값을 반환하기 때문에 힙에 접근을 하려면 주소 값을 이용해야 한다.

따라서 포인터를 이용해야지만 메모리 공간에 접근할 수 있다.

malloc 함수의 반환형이 void형 포인터인 이유와 힙 영역으로의 접근

malloc 함수의 반환형이 void형 포인터인 이유는 우리가 malloc에 전달하는 값이 숫자뿐이기 때문이다.

만약 4를 전달했다 하면, int형 변수로 사용할지 float형 변수로 사용할지, 길이가 4인 char형 배열로 사용할지 결정을 못하기 때문이다.

이 때문에 malloc 함수는 원하는 크기만큼 메모리 공간을 할당하고, 그 메모리의 주소 값을 반환하는 것이 끝이므로,

어떻게 사용할지는 포인터 형의 변환을 통해 직접 결정해야 하는 것이다.

malloc 함수의 호출을 통한 메모리 공간의 할당을 "동적 할당"이라 한다.

free 함수를 호출하지 않은 채 프로그램을 종료하면?

free 함수를 사용하지 않고 프로그램을 종료하면 malloc 함수로 할당된 메모리 공간이 남아있을까?

만약 남는다 가정하면, free 함수를 호출하지 않은 예제를 계속 실행하면 메모리 공간의 부족으로 운영체제의 실행에 문제가 생길 것이다. 하지만 이런 일이 일어날 리 없다.

프로그램 실행 시 할당된 모든 메모리 공간은 프로그램이 종료되면 운영체제에 의해 전부 해제되기 때문이다.

따라서 평상시 공부를 할 때 등의 경우에는 불필요하지만 실제 프로그램 구현에서는 반드시 호출해야 한다.

calloc 함수

calloc 함수 또한 힙 영역에 메모리 공간을 할당하는 함수이다.

malloc 함수와는 사촌 뻘 된다 볼 수 있는데, 두 함수의 차이점은 메모리 공간의 할당을 위한 인자의 전달 방식이다.

#include<stdio.h>
void *calloc(size_t elt_count, size_t elt_size);

malloc 함수는 인자를 한 개를 전달받았지만 calloc 함수는 두 개의 인자를 전달받는다.

malloc 함수가 "총 20바이트를 힙 영역에 할당해라"라면

calloc 함수는 "4바이트 크기의 블록(elt_size) 5개를(elt_count) 힙 영역에 할당해라"이다.

결과적으로는 완전히 동일하다.

한 가지 차이점이 더 있는데, malloc 함수는 할당된 메모리 공간을 별도의 값으로 초기화하지 않아 할당된 메모리 공간이 쓰레기 값으로 채워지지만 calloc 함수는 할당된 메모리 공간의 모든 비트를 0으로 초기화시킨다.

이런 특성 때문에 calloc 함수가 대신 사용되는 경우도 많다.

calloc 함수 또한 free 함수를 통해 할당된 메모리 공간을 해제한다.

realloc 함수

한번 할당된 메모리 공간은 크기를 확장할 수 없다. 이는 다른 영역에서는 불가능하지만, 힙 영역이면서 realloc 함수를 사용하면 가능하다.

#include<stdio.h>
void *realloc(void *ptr, size_t size);

realloc 함수의 첫 번째 전달인자로는 확장하고자 하는 힙 메모리의 시작 주소 값을 전달한다.

두 번째 전달인자에는 확장하고자 하는 메모리의 전체 크기를 전달한다.

ptr이 가리키는 메모리의 크기를 size 크기로 조절하는 것이다.

함수 호출의 성공 시에는 새로 할당된 메모리의 주소 값이 반환되며, 실패 시에는 NULL 값이 반환된다.

함수 호출의 형태는 다음과 같다.

int main() {
    int *arr = (int *)malloc(sizeof(int)*3);
    . . . .
    arr = (int *)realloc(arr, sizeof(int)*5);
}

위 코드의 실행 결과는 반환 값을 기준으로 두 가지로 나뉜다.

  • malloc 함수가 반환한 주소 값과 realloc 함수가 반환한 주소 값이 같은 경우
  • malloc 함수가 반환한 주소 값과 realloc 함수가 반환한 주소 값이 같지 않을 경우

전자는 기존에 할당된 메모리 공간의 뒤를 이어, 확장할 영역이 넉넉한 경우에 발생한다.

그렇지 않다면 힙의 다른 위치에 새로이 요구하는 크기의 메모리 공간을 별도로 할당해서 이전 배열에 저장된 값을 복사하기도 한다. 이러한 경우 후자의 경우와 같이 malloc 함수와 realloc 함수의 반환 값은 같지 않다.

728x90

댓글