우노
[Memory] 코드, 데이터, 스택, 힙 영역 본문
C언어의 메모리 구조
- 프로그램을 실행시키면, 운영체제는 우리가 실행시킨 프로그램을 위해, 메모리 공간을 할당해줍니다.
- 프로그램이 운영체제로부터 할당받는 대표적인 메모리 공간은 4가지입니다.
- 코드(code) 영역
- 데이터(data) 영역
- 스택(stack) 영역
- 힙(heap) 영역
메모리 영역 시각화
코드(Code) 영역
- 코드(Code) 영역은, 실행할 프로그램의 코드가 저장되는 영역으로, 텍스트 영역이라고도 부릅니다.
- CPU 는 코드 영역에 저장된 명령어를 하나씩 가져가서 처리하게 됩니다.
데이터(Data) 영역
전역 변수와 static 변수가 할당되는 영역입니다.
프로그램의 시작과 동시에 메모리에 할당되고, 프로그램이 종료되면 메모리에서 소멸됩니다.
예제 코드
#include <stdio.h> int a = 10; // 데이터 영역에 할당 int b = 20; // 데이터 영역에 할당 int main() { ... return 0; }
- 위와 같은 프로그램 실행 시,
- int형 변수 a, b 는 main 함수가 호출되기 전에 데이터 영역에 할당됩니다.
- 때문에, 프로그램이 종료될 때까지 메모리상에 존재합니다.
- 전역변수가 프로그램이 종료될 때 까지 존재하는 이유
예제 코드 시각화
스택(Stack) 영역
함수 호출 시 생성되는 지역 변수와 매개 변수가 저장되는 영역입니다.
함수 호출이 완료되면 사라집니다.
예제 코드
#include <stdio.h> void fct1(int); void fct2(int); int a = 10; // 데이터 영역에 할당 int b = 20; // 데이터 영역에 할당 int main() { int i = 100; // 지역변수 i가 스택 영역에 할당 fct1(i); fct2(i); return 0; } void fct1(int c) { int d = 30; // 매개변수 c 와 지역변수 d 가 스택영역에 할당 } void fct2(int e) { int f = 40; // 매개변수 e 와 지역변수 f 가 스택영역에 할당 }
- main 함수 와 fct1, fct2 라는 함수를 추가하였습니다.
- a, b 를 데이터 영역에 할당한 뒤
- main 함수를 호출하면
- int형 변수 i 는 지역변수로서 스택영역에 할당됩니다.
- 이후, fct1() 이라는 함수를 호출하면서, fct1 함수의 매개변수인 c 와 d 가 스택영역에 할당됩니다.
- fct1() 이라는 함수호출이 끝나면 c 와 d 는 스택영역에서 삭제되며,
- 이후, fct2() 라는 함수를 호출하면서, 매개변수 e 와 지역변수 f 가 스택영역에 할당됩니다.
- 스택영역은 그 이름그대로 스택의 성질을 띄고있습니다.
- 후입선출 구조
- 가장 늦게 저장된 데이터가 가장 먼저 인출됩니다.
- 후입선출 구조
예제 코드 시각화
힙(Heap) 영역
- 필요에 의해 동적으로 메모리를 할당 할 때 사용합니다.
힙 영역은 왜 필요할까?
코드 영역, 데이터 영역, 스택영역만 있으면 프로그램이 문제 없이 실행될 것 처럼 보입니다.
그렇다면, 힙영역은 왜 필요한 것일까요?
또한, 힙 영역은 프로그래머가 할당한다고 되어있는데,
언제 할당을 해야하는 걸까요?
배열을 예로 들어서 설명 하겠습니다.
int main() { // 정상적인 배열선언 int arr[10]; // 비 정상적인 배열선언 int i = 0; scanf("%d", &i); int arr[i]; return 0; }
- 배열의 길이를 사용자가 입력한 숫자로 잡아주는 것을, 비 정상적인 배열선언이라고 합니다.
- 왜 비 정상적일까요?
- 메모리 구조에 대해서 잘 파악하고 있다면 당연한 이야기입니다.
- 상단의 첫번째 그림을 다시보면,
- 스택 영역에 할당될 메모리의 크기는 컴파일 하는 동안 결정됩니다.
- 컴파일
- 개발자가 작성한 소스코드를 컴퓨터가 이해할 수 있는 기계어로 변환하는 작업
- 런타임
- 소스코드 파일을 실행가능한 소프트웨어 산출물로 만드는 일련의 과정
- 컴파일
- 정상적인 배열 선언의 경우,
- arr 이라는 배열의 크기가 40바이트 라는것을 알 수 있으며,
- 컴파일 과정에서, 미리 스택 영역에 arr 배열 영역을 할당해놓을 수 있습니다.
- 하지만 비 정상적인 배열선언의 경우,
- i 의 크기가 4바이트 라는 것을 알 수는 있으나, arr 라는 배열의 크기는 알 수 없어
- 스택 영역에 arr 배열 영역을 할당해놓을 수 없습니다.
그렇다면, 아래와 같이 배열을 선언할 때는 문제가 없을까요?
int main() { int i = 10; int arr[i]; return 0; }
- i 라는 변수가 10 이기 때문에, arr 라는 배열의 크기가 10 이라는 것을 알 수 있지 않을까요?
- 결과는 아닙니다.
- 컴파일을 하는 동안 i 가 4바이트의 크기라는 것을 알 수는 있으나,
- 그 값이 10 으로 초기화 되었다는 사실은 무시하고 넘어갑니다.
- 값이 10 으로 초기화 되었다는 사실은, 실행되는 동안(런타임)에 결정됩니다.
- 그렇기 때문에, 컴파일러는 arr 의 크기가 40바이트가 된다는 사실을 알 수 없으며,
- 스택 영역에 arr 배열 영역을 할당해놓을 수 없습니다.
- 따라서, 사용자의 요구에 맞게 arr 배열 메모리를 할당해 주기 위해서는
- 메모리 동적 할당을 통해, 힙 영역에 arr 배열 메모리를 할당해야합니다.
- 힙 영역
- 할당해야 할 메모리의 크기를, 프로그램이 실행되는 동안 결정해야 하는 경우(런 타임때) 유용하게 사용되는 공간
- 힙 영역
- 힙 영역을 사용하기 위해서는 동적할당에 대해서 공부해야합니다.
참고
'Operating System > Concept' 카테고리의 다른 글
[OS] 쓰레드 세이프(Tread Safe)란? (0) | 2022.06.18 |
---|---|
[OS] 프로세스, 쓰레드, 멀티 프로세스, 멀티 쓰레드란? (0) | 2022.06.17 |
Comments