포스트

메모리 구조(세그먼트)

본 글은 제 개인적인 공부를 위해 작성한 글입니다. 틀린 내용이 있다면 언제든지 피드백을 주시면 감사하겠습니다. 참고로만 활용해주시길 바랍니다.

메모리 구조(세그먼트)


프로그램이 실행되기 위해서는 먼저 프로그램이 메모리에 로드되어야 한다.

그리고 프로그램에서 사용되는 변수들을 저장할 메모리도 필요하다.

따라서 프로그램을 실행시키면 OS는 우리가 실행시킨 프로그램을 위해 메모리 공간을 할당해준다.

C의 메모리 구조텍스트(코드)영역, 데이터 영역, BSS 영역, 힙 영역, 스택 영역 등 다섯개의 영역으로 구분된다.

영역 = 세그먼트

image

1) 텍스트(코드) 세그먼트


텍스트 세그먼트에는 프로그램의 코드들이 바이너리화 되어 저장된다.**

프로세서(CPU)는 텍스트 영역에 저장된 명령어를 하나씩 가져가서 처리한다.

  1. 변수가 아닌 코드만 저장하고 있기 때문에, 쓰기가 금지되어 있다.
  2. 읽기 전용일 때 장점으로는 한 종류의 프로그램을 여러 번, 여러 개 실행해도 텍스트 세그먼트를 공유할 수 있다는 것이다.

    가령 메모장을 3개, 4개 켜더라도 RAM에 텍스트 세그먼트를 3개, 4개 올릴 필요가 없다.

  3. 텍스트 세그먼트의 명령 실행 순서는 순차적이지 않다. 왜냐하면 하이 레벨의 언어 제어구조가 어셈블리어의 branch, jump, call 등으로 변형되기 때문이다.
  4. 바뀌는 것이 없으므로 크기가 고정이다.

2) 데이터 세그먼트


데이터 세그먼트는 프로그램의 전역 변수정적 변수가 저장되는 영역이다.

이 공간에는 특히 초기값이 있는 전역변수, 배열, static으로 선언된 변수가 들어간다.

이 공간은 프로그램 런타임에 자유롭게 수정 및 변경이 가능하다.

프로그램의 시작과 동시에 할당되고, 프로그램이 종료하면 소멸한다.

1
2
3
4
5
6
7
8
9
#include <stdio.h>

int a = 10;	// 데이터 세그먼트에 할당
int b = 20;	// 데이터 세그먼트에 할당

int main() {
	...
	return 0;
}

변수 a, b는 프로그램 실행 시 main()이 호출되기 전에 데이터 세그먼트에 할당된다.

그렇기 때문에 전역 변수는 프로그램이 종료될 때까지 메모리 상에 존재한다.

3) BSS(Block Starting Symbol) 세그먼트


1
2
3
4
5
6
7
8
9
10
11
12
#include <stdio.h>

// 아래의 전역 변수들은 초기값이 할당되어있지 않기 떄문에,
// BSS 세그먼트에 할당되게 된다.
int uninitializedInt;
char uninitializedChar;

int main()
{
	...
	return 0;
}

BSS 세그먼트에는 정적/전역 변수 중 초기화되지 않은 변수들이 저장되는 공간이다.

BSS 세그먼트의 한 가지 주요 특징은, 프로그램이 실행될 때까지 실제 메모리를 차지하지 않는 특징을 가지고 있다.

프로그램이 디스크에 저장되는 시점에서는 실제 메모리 공간을 차지하지 않고, 프로그램이 실행될 때 운영체제는 이 변수들에 대한 메모리 공간을 할당하고, 이 공간을 0으로 초기화 한다.

  • 이는 변수가 명시적으로 초기화되지 않았을 때, 그 값이 예측불가능한 상태가 되는 것을 방지하고 메모리를 효율적으로 사용할 수 있다.
  • 따라서 BSS 세그먼트의 변수들은 프로그램이 실행되기 전에는 모두 0의 값을 가진다. (C에서 정적/전역 변수에 값을 할당하지 않으면 0이 되는 이유)

따라서 전역변수를 선언한다면, 초기화를 하지 않는 것이 좋다.

4) 스택 세그먼트


스택 세그먼트함수의 호출과 관계되는 지역변수매개변수가 저장되는 영역이다.

스택 세그먼트는 컴파일 타임에 크기가 결정되고, 함수의 호출과 함께 할당되며, 함수의 호출이 완료되면 소멸한다.

이렇게 스택 영역에 저장되는 함수의 호출 정보를 스택 프레임 Stack Frame이라고 한다.

스택 영역은 Push 동작과 Pop 동작이 있고, 후입선출(LIFO, Last-In First-Out) 방식에 따라 동작한다.

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
#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가 스택영역에 할당
}

전역변수 a, b데이터 영역에 할당한 뒤에 main()을 호출하면서 지역변수 i스택 영역에 할당

fct1()를 호출하면서 fct1()의 매개변수인 c와 지역변수 d스택 영역에 할당

fct1() 함수 호출이 끝나면 cd는 스택 영역에서 삭제된다.

fct2()를 호출하면서 fct2()의 매개변수인 e와 지역변수 f스택 영역에 할당

fct2() 함수 호출이 끝나면 ef는 스택 영역에서 삭제된다.

5) 힙 세그먼트


힙 세그먼트는 프로그램에서 동적으로 할당되는 메모리가 저장되는 영역이다.

힙 세그먼트는 런타임에 동적으로 크기가 결정된다.

프로그램이 실행되는 동안 프로그래머에 의해 메모리 공간을 할당하고 해제할 수 있다.

힙 영역은 malloc(), calloc(), realloc()과 같은 동적 메모리 할당 함수를 사용하여 사용자가 직접 관리해야 한다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include <stdio.h>
#include <stdlib.h>

int main() {
	int* ptr = (int*)malloc(sizeof(int));	// 힙 영역에 메모리 할당

	if (ptr == NULL) {
		printf("메모리 할당에 실패하였습니다.");
		return -1;
	}

	*ptr = 10;	// 할당된 메모리에 값 저장

	printf("%d\\n", *ptr);	// 저장된 값 출력

	free(ptr);	// 메모리 해제

	return 0;
}

위의 예시에서 malloc() 함수를 사용하여 int형 변수를 위한 메모리를 동적으로 할당하고, 할당된 메모리에 값을 저장한 뒤 출력했다.

마지막으로 free() 함수를 사용하여 메모리를 해제하였다.

참고

이 기사는 저작권자의 CC BY 4.0 라이센스를 따릅니다.