우리가 프로그램을 작성하여 실행시키면 OS에 의해 메모리 공간이 할당된다. 바로 RAM영역이다. 할당된 영역은 크게 3가지로 나뉜다. 아래 그림을 보자.
Text 영역 : 문자열상수등이 저장된다.
Data 영역 : 전역변수, static 변수등이 Data영역에 저장된다.
Heap 영역 : 동적할당메모리 영역이며 Stack보다 공간이 크다.
Stack 영역 : 지역변수, 매개변수 등이 관리되는 영역으로 자동으로 관리된다.
한번 아래 코드를 보자.
#include <stdio.h>
#include <stdlib.h>
int A;
static int B;
char str[] = "MemoryAreaTest";
int main()
{
int N=4;
static int C;
int arr[N];
char str2[] = "MemoryAreaTest";
const char str3[] = "MemoryAreaTest";
int* mp = (int*)malloc(N*sizeof(int)); //동적메모리할당
int* cp = (int*)calloc(4,sizeof(int)); //동적메모리할당
printf("========= Data Area =========\n"); //Data 영역
printf("A address : %#x\n",&A); //Data 영역
printf("B address : %#x\n",&B); //Data 영역
printf("C address : %#x\n",&C); //Data 영역
printf("str address : %#x\n",str); //Data 영역
printf("\n========= Stack Area =========\n"); //stack 영역
printf("str2 address : %#x\n",str2); //stack 영역
printf("str3 address : %#x\n",str3); //stack 영역
printf("N address : %#x\n",&N); //stack 영역
printf("arr : %#x\n",arr); //stack 영역
printf("\n========= Heap Area =========\n"); //Heap 영역
printf("mp : %#x\n",mp); //heap 영역
printf("cp : %#x\n",cp); //heap 영역
printf("\n========= Text Area =========\n"); //Text 영역
printf("MemoryAreaTest : %#x\n", &"MemoryAreaTest"); //Text 영역
printf("\n");
free(mp); //동적메모리 해제
free(cp); //동적메모리 해제
return 0;
}
위 코드를 돌려보면 각 변수들이 할당된 주소를 알수가 있다. 우선 실행 결과를 보자.
같은 영역으로 예상되는 변수들끼리 주소값이 비슷한 것을 알 수 있다.
Data 영역
코드를 보면 전역변수 A, static 전역변수 B, static 지역변수 C, 그리고 문자열 전역변수 str이 Data영역으로 구분되어 있다. 빌드하는 환경에 따라 실제 주소값을 다르겠으나 우리가 이해했던 개념대로 Data영역임을 짐작할 수 있다. Data 영역의 메모리는 프로그램이 시작될 때 할당되며, 프로그램이 종료될때까지 메모리에서 소멸하지 않는다. 우리가 이해하고 있는 전역변수, static 변수의 개념과 동일하다. 즉, A, B, str변수는 main함수가 호출되기 이전에 Data영역에 할당된다.
Stack 영역
Stack 영역은 일반적인 매개변수, 지역변수들이 관리되는 영역이다. 자동으로 관리되며 해당 함수의 scope를 벗어나면 메모리는 소멸하게 된다. 모든 할당과 소멸은 고맙게도 자동이다. str2, str3, N, arr변수 등 자료형이나 const와 상관 없이 모두 Stack 영역임을 확인할 수 있다. Stack 영역은 말그대로 Stack 자료구조처럼 동작하게 된다. 아래와 같이 변수가 Stack영역에 관리될 것이다.
Heap영역
Heap영역은 동적메모리할당에 사용되는 공간이다. Stack보다 공간이 크나 Stack과는 달리 메모리 관리가 자동으로 되지 않는다. 즉, 사용자에 의해 할당 및 해제가 이루어져야 한다. 우리가 알고 있는 malloc, calloc을 사용하게 되는데 사용법은 아래 글을 참고하자.
2021.09.02 - [SW/C] - [동적메모리할당] malloc, calloc 사용법
Stack보다 엑세스가 느리고 오사용에 의한 메모리누수의 위험성이 있지만 동적메모리할당을 통해 런타임중에 메모리를 할당할 수 있다는 점에서 의미가 있다. 위의 코드에서는 mp, cp가 각각 malloc과 calloc을 통해 동적메모리할당이 되었는데 주소값에서의 차이를 보아 Heap영역임을 알 수 있다.
Text영역
위의 코드에서 보면 문자열 변수 str, str2, str3에 "MemoryAreaTest"를 대입하고 있다. 우리가 int x = 3등의 상수를 대입하듯, 문자열'변수'에 "MemoryAreaTest"라는 문자열'상수'를 대입하는 것이다. 상수는 변하지 않는 값이다. 즉, "MemoryAreaTest" 역시 변할 수 없다는 말이다. 그럼 "MemoryAreaTest"라는 어디에 저장되고 관리될까? 바로 Text 영역이다. Text영역에는 "MemoryAreaTest"과 같은 문자열상수들이 관리된다. char* p등의 포인터 변수를 통해 문자열 상수를 가리키고 해당 값을 변경시키려한다면 런타임 에러가 발생할 것이다. 상수를 변경하려고 했기 때문이다. 위 코드의 결과값 역시 "MemoryAreaTest"의 주소값의 구성이 여타 다른 영역의 값과 다른 것을 알 수 있다.
메모리 영역에 대한 개념은 다소 노잼이고 복잡할 수 있으나 동작의 기본 원리이므로 꼭 이해해두고 있도록 하자.
'SW > C' 카테고리의 다른 글
[VLA] Variable-length Array, 가변 길이 배열 (1) | 2021.09.03 |
---|---|
[동적메모리할당] malloc, calloc 사용법 (0) | 2021.09.02 |