C 프로그램 메모리 구조
C 프로그램 메모리 구조는 일반적으로 다음의 섹션으로 나타낸다.
- Text segment
- Initialized data segment
- Uninitialized data segment
- Stack
- Heap
high address+----------------------+
| |command+line arguments
| |and environment variables
+----------------------+
| stack |
| + |
| | |
| v |
| |
| ^ |
| | |
| + |
| heap |
+----------------------+
| uninitialized data |initialized to
| (bss) |zero bt exec
+----------------------+
| initialized data |read from
+----------------------+program file
| text |by exec
low address+----------------------+
Text segment
Text Segmnt는 Code Segment나 간단히 Text라고 불리는 섹션으로 실행 명령어로 구성된다. 메모리 영역에서 Text segment는 Heap이나 Stack의 아래에 위치하여 heap, stack overflow 및 overwriting을 막는다. 보통 텍스트 에디터, 컴퍼일러, 쉘와 같이 빈번히 실행되는 프로그램은 Text segment에 한번만 복사하여 단일 복사본을 공유한다. 또한 Text segment는 읽기 전용 제공되어 프로그램의 명령어 수정을 막는다.
Initialized data segment
Initialized data segment는 보통 Data Segment로 불린다. Data segment는 프로그램의 가상 메모리 역역에 위치하여 프로그래머가 초기화한 전역 변수나 정적 변수를 포함한다. 프로그램이 실행되는 동안 변수 값이 변경되므로 Data segment는 읽기 전용이 아니다. 이 섹션은 초기화된 읽기 전용 영역과 초기화된 읽기/쓰기 영역으로 분류할 수 있는데, 예를 들어 C에서 char s[] = "hello world"
로 정의된 전역 문자열과 외부(전역)의 int debug = 1
같은 명령문은 초기화된 읽기/쓰기 영역에 저장된다. 그리고 const char * string = "hello world"
와 같은 C 명령문은 “hello world” 문자열 그대로를 초기화된 읽기 전용 영역에 저장하고 문자 포인터 변수 문자열 값을 초기화된 읽기/쓰기 영역에 저장한다.
Ex. static int i = 10
과 globalint i = 10
은 Data segment에 저장된다.
Uninitialized data segment
Uninitialized data segment는 오래된 어셈블러 연산자 “block started by symbol”의 이름을 따서 bss segment라고 불린다. 이 세그먼트의 데이터는 프로그램이 실행되기 전에 커널에 의해 산술 값 0으로 초기화된다. Uninitialized data는 Data segment 끝에서 시작하며 소스코드 상에서 초기화되지 않았거나, 0으로 초기화한 모든 전역 변수와 정적 변수를 포함한다.
Ex. static int i;
나 globalint j;
는 BSS segment에 포함된다.
Stack
Stack 영역은 Heap 영역과 인접해있으며 반대 방향으로 확장된다. 여유 메모리 공간이 고갈된다면 Stack 포인터와 Heap 포인터가 만나게 된다. (현대의 큰 주소 공간과 가상 메모리 기법을 사용하여 거의 모든 곳에 배치할 수 있지만, 일반적으로 반대 방향으로 성장한다.)
Stack 영역은 LIFO 구조로 일반적으로 높은 주소 영역에 위치해있다. PC x86 컴퓨터 시스템 구성에서 0주소를 향해 확장된다. (반대 방향으로 확장하는 시스템 구성도 존재한다.) Stack 포인터 레지스터는 스택의 꼭대기에서 나아가며, 값이 스택에 PUSH 될 때 마다 조정된다. 함수 호출에 의해 PUSH된 값의 집합을 Stack Frame이라고 하며 Stack Frame에는 최소한 return address가 포함된다.
Stack은 자동으로 함수 호출 시 정보와 변수가 자동 저장되는 곳이다. 함수가 호출될 때마다 호출자의 환경에 대한 정보와 컴퓨터 레지스터와 같은 특정 정보가 Stack에 저장된다. 새롭게 호출된 함수는 Stack에 자동 변수와 임시 변수를 위한 공간을 할당한다. 이는 재귀 함수가 작동되는 방식으로 재귀 함수가 자신을 호출할 때 마다 새 스택 프레임이 사용되므로 한 세트의 변수는 다른 함수 인스턴스의 변수와 간섭을 일으키지 않는다.
Heap
Heap은 주로 동적으로 메모리 할당한다. Heap은 BSS segment 끝에서 시작하여 높은 주소 방향으로 확장된다. Heap 영역은 malloc, realloc, free에 의해 관리되며, brk 및 sbrk 시스템 호출을 사용하여 크기를 조정할 수 있다. (malloc, realloc, free를 이행하기 위해서 반드시 brk 및 sbrk와 단일 Heap 역역의 사용이 동반되지는 않는다. 가상 메모리의 프로세스 가상 주소 공간이 인접하지 않게 예약하기 위해 mmap을 사용할 수 있다.)Heap 영역은 프로세스의 모든 공유 라이브러리와 동적으로 로드된 모듈에 의해 공유된다.
Example
size
명령어를 이용하여 text, data, bss segment의 크기(byte)를 살펴보자.
- 간단한 C 프로그램을 살펴보자.
#include <stdio.h>
int main(void)
{
return 0;
}
[narendra@CentOS]$ gcc memory-layout.c -o memory-layout
[narendra@CentOS]$ size memory-layout
text data bss dec hex filename
960 248 8 1216 4c0 memory-layout
- 프로그램에 전역 변수를 추가하고 bss 크기를 확인하자.
#include <stdio.h>
int global; /* Uninitialized variable stored in bss*/
int main(void)
{
return 0;
}
[narendra@CentOS]$ gcc memory-layout.c -o memory-layout
[narendra@CentOS]$ size memory-layout
text data bss dec hex filename
960 248 12 1220 4c4 memory-layout
- 정적 변수 하나를 추가하고 bss에 저장되는 것을 확인하자.
#include <stdio.h>
int global; /* Uninitialized variable stored in bss*/
int main(void)
{
static int i; /* Uninitialized static variable stored in bss */
return 0;
}
[narendra@CentOS]$ gcc memory-layout.c -o memory-layout
[narendra@CentOS]$ size memory-layout
text data bss dec hex filename
960 248 16 1224 4c8 memory-layout
- 초기화한 정적 변수가 Data segment에 저장되는 것을 확인하자.
#include <stdio.h>
int global; /* Uninitialized variable stored in bss*/
int main(void)
{
static int i = 100; /* Initialized static variable stored in DS*/
return 0;
}
[narendra@CentOS]$ gcc memory-layout.c -o memory-layout
[narendra@CentOS]$ size memory-layout
text data bss dec hex filename
960 252 12 1224 4c8 memory-layout
- 초기화된 전역 변수가 Data segment에 저장되는 것을 확인하자.
#include <stdio.h>
int global = 10; /* initialized global variable stored in DS*/
int main(void)
{
static int i = 100; /* Initialized static variable stored in DS*/
return 0;
}
[narendra@CentOS]$ gcc memory-layout.c -o memory-layout
[narendra@CentOS]$ size memory-layout
text data bss dec hex filename
960 256 8 1224 4c8 memory-layout