일러두기
본 글은 국비지원 교육과정을 듣는 학생이 메모리 구조에 대해 공부한 것을 바탕으로 적은 글입니다. 초보자가 서술한 글인만큼 정보에 다소간의 오류가 있을 수 있습니다!
컴퓨터 내에서의 프로그램 실행 순서
메모리 구조에 대해 이야기를 하기 전에 우선 컴퓨터 프로그램이 실행되는 일련의 과정을 메모리의 측면에서 알아보자.
- 첫 번째, 사람이 컴퓨터에게 프로그램 실행을 요청한다.
- 두 번째, 프로그램 실행 요청을 받은 운영체제(OS)는 해당 프로그램의 정보를 읽은 후 이를 메모리에 로드한다.
- 세 번째, 이 때 OS는 주기억장치(RAM)에 4가지의 공간을 할당하며 이는 각각 Code, Data, Stack, Heap 영역이다.
- 네 번째, OS에 의해 할당된 메모리는 중앙처리장치(CPU)에 의해 관리되며, CPU는 프로그램 코드에 기입된 명령문을 실행한다.
- 다섯 번째, 프로그램이 실행된다.
메모리 구조
1. 코드영역
코드영역은 text영역으로도 불리우며 CPU에서 순차적으로 실행되는 함수와 연산 구문등이 담긴 명령어와 전역 상수가 기계어의 형태로 저장되는 영역이다. 실행할 프로그램의 소스코드가 저장되는 영역이기 때문에 코드영역이라고 불린다.
2. 데이터영역
프로그램이 시작됨과 함께 할당되어 프로그램이 종료되는 시점에 소멸하는 메모리 영역이다. 프로그램의 전역 변수와 정적(static) 변수 등이 저장되는 공간이다. Data영역과 BSS영역을 통틀어 데이터영역이라 표현하는데 초기화가 된 데이터는 data영역에, 초기화가 되지 않은 데이터는 BSS(Block Stated Symbol)영역에 저장된다.
3. 스택영역
함수의 호출과 관계되는 지역 변수와 매개 변수가 저장되는 영역이다. 영어단어 stack은 명사형일 때는 '(보통 깔끔하게 정돈된) 무더기'라는 뜻을, 동사형일 때는 '(깔끔하게 정돈하여) 쌓다'라는 뜻을 가진 단어로 사진처럼 가지런히 쌓아놓은 책을 생각하면 편하다. 함수가 호출되면 왼쪽 사진의 책이 한권 한권 쌓여가듯 함수가 하나하나씩 쌓여간다. 그리고 함수가 종료되면 완전히 소멸한다.
스택영역의 메모리는 나중에 호출된 것이 가장 먼저 소멸한다는 후입선출(LIFO, Last In First Out)의 방식에 의해 동작하기 때문에 데이터 추출 시, 오직 가장 최근에 할당된 데이터에만 접근이 가능하다.
힙영역에 비해 메모리 할당량이 작기 때문에 덩치가 큰 메모리를 사용할 때는 힙영역에 메모리를 할당하고 스택영역에서 참조하는 방식을 사용한다.
힙영역과는 사실상 같은 메모리를 공유하는데, 스택영역은 상위주소에서 시작해서 하위주소로 메모리가 할당되고 힙영역은 하위주소에서 시작해서 상위주소로 메모리가 할당된다. 즉, 스택영역의 확장은 곧 힙영역의 축소를 의미하므로 보통의 컴파일러는 스택영역의 메모리 할당량을 1MB로 제한하여 힙영역이 과도하게 축소되는 상황을 미연에 방지한다. (종료되지 않는 재귀함수Recursive Function를 사용할 때 stack overflow라는 에러를 만나게 되는데 이는 함수가 종료되지 않고 무한히 호출되면서 스택영역에 할당 가능한 메모리 용량을 초과해 버리기 때문에 발생하는 현상이다.)
4. 힙영역
프로그래밍 시 자유롭게 할당하고 해체할 수 있는 메모리 영역으로 프로그래머가 직접 관리할 수 있는 영역이다. 스택영역에 비해 메모리를 할당할 수 있는 용량이 훨씬 크기 때문에 대량의 데이터는 힙영역에 할당하고 스택영역에서는 힙영역의 주소를 참조하여 사용하는 경우가 코딩에서 자주 일어난다. 대표적인 예가 바로 배열과 객체이다. 32bit 운영체제에서는 약 2GB를, 64bit에서는 OS상에서 지원가능한 최대치까지를 힙영역에 할당하여 사용할 수 있다.
힙영역은 사용자에 의해 메모리가 동적으로 할당되고 해제된다는 특징을 가지고 있는데, 이러한 특징 때문에 발생할 수 있는 문제가 바로 메모리 누수(Memory Leak)이다. 메모리 누수가 발생할 경우 프로그램이 실행되는 동안 지속적으로 불필요한 메모리가 사용되기 때문에 장기적으로 시스템에 치명적인 문제를 일으킬 여지가 있다.
메모리 누수를 막기 위해서는 프로그래머가 직접 메모리 관리를 해주어야 하는데, Java, C#과 같은 고수준의 언어에서는 힙영역의 메모리를 관리해주는 Garbage Collector(GC)라는 기능이 존재해 프로그래머가 별도의 관리를 하지 않아도 된다. (그러나 GC의 능력은 완벽하지 않기 때문에 메모리 관리를 할 수 있는 프로그래머는 그렇지 않은 프로그래머보다 퍼포먼스적인 측면에서 우위를 점할 수 있다고 생각한다.) C / C++과 같은 언어에서는 힙영역을 관리해주는 별도의 장치가 없기 때문에 C / C++ 프로그래머에게 메모리 관리는 정말로 중요하다.
정리
- 프로그램이 실행되면 OS는 주기억장치에 Code, Data, Stack, Heap의 4가지 공간을 할당한다.
- 코드영역에는 소스코드가 저장되며 명령어, 전역 상수가 기계어의 형태로 저장된다.
- 데이터영역에서는 전역 변수와 정적 변수가 저장되며 프로그램이 끝날 때까지 소멸되지 않는다.
- 스택영역에는 함수의 호출과 관련되는 지역 변수, 매개 변수가 저장된다. 스택영역의 메모리는 수시로 바뀌기 때문에 스택영역에 저장되는 변수는 프로그래머가 초기화하지 않으면 사용할 수 없다.
- 힙영역은 프로그래머에 의해 관리되는 영역이며 대량의 데이터를 저장할 수 있는 영역이다. Java의 경우 객체가 힙영역에 저장되며 배열의 변수값 또한 이곳에 저장된다. 실제 사용자가 사용하는 데이터가 이곳에 저장된다고 보면 될듯.
'자료구조' 카테고리의 다른 글
자료구조 : Stack과 Queue 그리고 Tree와 Heap (0) | 2022.02.08 |
---|