728x90
Intro
- 프로그램을 실행시킬 때 메모리에 로드되어 프로그램이 실행되는 과정에서 OS는 메모리(RAM) 에 공간을 할당해준다. 그렇지만 RAM 은 제한된 양을 가지고 있어서 이 제한된 스토리지를 어떻게 하면 효율적으로 사용할 수 있을지를 결정해야 할 것이다.
- 따라서 개발자 (사용자) 입장에서는 memory 구조를 알면 프로그램에 의해 사용되는 메모리의 양을 결정할 때 유용할 것이다.
- 각각의 영역은 개별적인 read-write 권한을 가진다.
코드(텍스트) 영역
- 개발자가 작성한 소스코드가 들어가는 부분이다. 텍스트 영역이라고도 부른다.
- 프로그램이 컴파일 된 후에, 바이너리 파일이 생성되고 이 바이너리 파일이 RAM에 로드된다. 바이너리 파일에 포함되어 있는 명령어들이 (함수, 제어문, 상수 등) 코드 영역에 저장된다.
- read-only permission : 코드 영역은 프로그램의 갑작스러운 변경을 방지하기 위해서 read-only 권한으로 실행된다.
- CPU는 코드 영역에 저장된 명령어들을 하나씩 가져가서 연산을 실행한다.
데이터 구조를 조금 더 세분화해서 살펴보면 다음의 그림과 같다.
데이터 영역
데이터 영역은 Initialized Data Segment와 Uninitilaized Data Segment 둘로 나뉜다.
1. Initialized Data Segment
- external, global, static, constant 변수들 (전역변수 & 정적변수)을 포함하며, 가상메모리가 할당되는 영역이다.
💡 변수 키워드 정리
external : 다른 파일에 같은 이름의 전역 변수가 존재한다는 것을 표시만 하고 선언은 하지 않는다.
global : 어느 위치에서든 참조해서 사용할 수 있는 변수
static : 선언 후에 그 위치에 상관없이 프로그램의 시작부터 끝까지 메모리에 할당되어 있으며, 값의 변경이 가능하다.
const : 해당 변수를 초기화한 이후에는 값을 변경할 수 없다.
- read-write permission : 변수들의 값은 프로그램이 실행되는 동안 변할 수 있기 때문에 read write 권한으로 실행된다. 세분화하면 다음과 같다.
- read-only area : const variable
- read-write area : const variable 이외의 다른 변수들
- 프로그램이 시작되면 할당되고, 프로그램이 종료되면 소멸되는 영역이다.
예를 들어, 다음과 같은 const 포인터 변수가 있다고 하자.
const hello* = "Data segment";
hello 라는 포인터 변수는 read-write 영역에 할당되고, “Data segment” 라는 string 값 자체는 read-only 영역에 할당될 것이다.
2. Uninitialized Data Segment
- BSS (Block started by symbol) 이라는 이름으로도 알려져 있다.
- BSS의 모든 데이터는 프로그램이 실행되기 이전에 kernel에 의해 숫자 값 0 도는 포인터의 경우 NULL 포인터로 초기화 된다.
- BSS 또한 static , global 변수들을 포함한다.
- read-write permission : 데이터의 값이 변경될 수 있다.
Code Example
#include <stdio.h>
// 초기화 되지 않은 전역변수는 bss영역에 할당된다.
int global_variable;
int main()
{
// 초기화 되지 않은 static variable bss 영역에 할당된다.
static int static_variable;
// ..
printf("global_variable = %d\\n", global_variable);
printf("static_variable = %d\\n", static_variable);
return 0;
}
Output
초기화 되지 않은 int 타입 변수의 경우 프로그램 실행 전에 0으로 초기화 된다.
global_variable = 0
static_variable = 0
스택 영역
- LIFO (Last In First Out) 를 따르는 스택 영역은 점점 lower address 로 향하며 메모리가 할당 된다. → 이는 컴퓨터 구조에 따라서 달라질 수 있다.
- 지역 변수, 함수의 매개변수 (parameter)가 저장되며 함수 호출이 완료되면 사라진다.
- 컴파일 타임에 스택 영역의 크기가 결정된다.
- Stack frame : 함수가 호출되면 새로운 stack frame이 생성된다. stack frame에 함수 내부의 변수 및 함수의 return 주소 및 함수 호출자의 환경과 같은 추가적인 정보를 저장한다. 재귀함수의 경우에도 호출될 때마다 새로운 stack frame이 개별적으로 생성된다.
#include<stdio.h>
void foo() {
// local variables stored in the stack
// when the function call is made
int a, b;
}
int main() {
// local variables stored in the stack
int local = 5;
char name[26];
foo();
// ..
return 0;
}
- 처음으로, main() 함수가 실행되고, main() 함수의 stack frame 이 만들어 진다. 이 stack frame 은 local, name 변수는 stack frame에 포함되어서 stack 에 push 된다.
- foo()함수가 호출된다. 또 다른 stack frame이 생성된다. 새롭게 만들어진 foo stack frame은 개별적으로 stack에 push 된다. 변수 a, b 는 이 stack frame에 포함되어 stack에 push 된다.
- stack frame이 pop 되면서 변수들이 메모리 할당 해제되고, 프로그램이 종료될 때 main 함수의 stack frame 또한 pop 될 것이다.
힙 영역
- 런타임 동안에 할당되는 동적할당 메모리이다.
- Stack 영역과 반대 방향으로 grow / shrink 한다.
- 프로그래머가 직접 메모리를 할당 및 해제하는 메모리 공간이다. 해당 언어에서 가비지 컬렉터를 지원하는 경우 자동으로 메모리 해제를 한다. (ex. Java, C#..)
💡 가비지 컬렉터(Garbage Collector) 란 ?
가비지 컬렉터 는 다음과 같은 일을 한다.
1. 메모리 할당
2. 사용 중인 메모리 인식
3. 사용하지 않는 메모리 인식
메모리가 부족할 때 쓰레기(garbage)를 정리해주는 역할을 담당하는 프로그램이다. 할당된 메모리들은 프로그램이 종료되면 필연적으로 garbage가 발생하게 된다. 기존에 가리키고 있던 메모리가 할당 해제되고 나서 새로운 곳을 가리키게 되면서 주소를 잃어버리게 된다. 따라서 정리되지 않은 메모리가 생기게 된다.
단, 가비지 컬렉터가 존재하더라도 더 이상 접근 불가능한 객체만 회수하기 때문에 메모리 누수가 생길 수 있다.
- C의 malloc, calloc, free, realloc 와 같은 명령어 사용하여 메모리 할당 및 해제 관리
- 클래스, 클로저가 힙 영역에 저장된다.
자료 출처
https://www.scaler.com/topics/c/memory-layout-in-c/
728x90
'Computer Science > 운영체제' 카테고리의 다른 글
[OS] 운영체제 4. 시스템의 구조와 프로그램의 실행 (0) | 2023.05.21 |
---|---|
[OS] 운영체제 3. 컴퓨터 시스템 구조 (0) | 2023.05.20 |
[운영체제] Process와 Thread의 차이 (0) | 2023.03.30 |
[운영체제] 세마포어와 뮤텍스 알고리즘 (1) | 2023.01.16 |
[운영체제] 인터럽트 (Interrupt) (0) | 2023.01.08 |