1. 개요
코드를 작성하고 프로그램으로 만들어 실행시키면 개발자가 작성했던 모든 코드와 데이터는 메모리에 저장된다.
프로그램이 동작한다는 것은 CPU가 메모리에 저장된 명령어를 실행하고, 데이터를 변경하는 과정이다.
그만큼 코드를 작성할 때 메모리는 중요하고, 메모리에 대해 이해하면 프로그램의 동작을 쉽게 이해할 수 있다.
2. 메모리의 구조
일반적으로 검색하면 볼 수 있는 메모리구조이다.
각 영역의 특징과 차이점을 알아보고자 한다.
3. 메모리 영역
우선 프로그램의 작동 과정에 대해 간단하게 설명하겠다.
개발자가 코드를 작성한 후 컴파일을 통해 실행파일로 변경하고, 사용자가 실행파일을 실행하면 프로그램이 작동한다.
이때 컴파일하는 과정을 컴파일타임(Compile time), 프로그램이 작동하는 동안의 시간을 런타임(Run time)이라고 한다.
3.0. Low level, High level
- 메모리 구조를 찾다보면 low level, low address, low memory 등 다양하게 표현되는데, 결국 다 비슷하게 메모리가 저장된 주소를 의미한다.
- 메모리가 0x0000부터 0xFFFF까지 있다고 가정할 때, 0x0000쪽이 Low level, 0xFFFF쪽이 High level이다.
3.1. Code 영역
코드영역, 혹은 텍스트 영역이라고도 불린다.
작성한 함수와 명령어, 그리고 const로 지정된 상수가 저장된다.
컴파일 타임에 크기가 결정되며, 프로그램을 실행시킬 때 데이터가 메모리에 저장되고 프로그램이 종료될 때 소멸한다.
런타임동안 CPU가 Code영역에 저장된 명령어와 함수를 읽어와 실행한다.
컴파일 타임에 한번 데이터를 저장하면 런타임동안 Code영역의 데이터를 수정할 수 없다.
3.2. Data 영역
전역변수, 정적변수(static), 외부변수(extern)가 저장된다.
코드영역과 마찬가지로 컴파일 타임에 크기가 결정되며, 프로그램을 실행시킬 때 메모리에 저장되고 프로그램이 종료될 때 소멸된다.
런타임동안 Data영역의 값을 변경할 수 있다.
추가로, Data영역은 변수 초기화 여부에 따라 Data영역, BSS영역으로 구분된다.
변수를 선언할 때 초기화를 했으면 Data영역, 초기화하지 않고 선언만 했으면 BSS영역에 저장된다.
3.3. Heap 영역
동적으로 할당하는 변수의 데이터가 저장된다.
크기가 따로 정해지지 않으며, 런타임동안 메모리를 할당할 때 데이터가 저장되고 할당을 해제하면 데이터가 소멸한다.
데이터를 해제하지 않으면 프로그램이 종료될때까지 데이터가 유지된다.
다른 영역은 고정된 크기를 갖지만, Heap영역은 크기가 결정되지 않고 메모리가 허용하는 한 자유롭게 사용가능하다.
데이터의 크기가 확실하지 않을 때 사용한다.
사용하지 않는 데이터를 적절히 해제하지 않으면 메모리 누수(memory leak)가 발생한다.
포인터로 접근하며 매번 새로운 위치에 데이터를 할당, 해제하기 때문에 읽기, 쓰기 속도가 상대적으로 느리다.
3.4. Stack 영역
배열과 지역변수, 매개변수, 포인터 등이 저장된다.
컴파일 타임에 크기가 할당되며, 런타임에 함수가 호출될 때 데이터가 저장되고 함수가 종료될 때 데이터가 소멸된다.
Stack영역의 값은 변경이 가능하다.
컴파일 타임에 크기가 정해지기 때문에 런타임에 데이터가 일정 크기 이상 할당될 수 없다.
정리
4. Heap과 Stack 영역의 비교
메모리 구조 사진을 보면 다른 메모리들은 영역이 확실하게 구분되어 있지만 Heap과 Stack영역은 서로의 영역이 확실하지 않다.
두 메모리는 같은 공간을 공유하며 서로 반대방향으로 데이터를 저장한다.
Heap 영역
먼저 추가한 데이터는 낮은 주소, 나중에 추가한 데이터는 높은 주소에 저장된다.
Heap영역에 동적 메모리가 해제되지 않고 계속 쌓여 Stack영역을 침범한다면 Heap over flow 에러가 발생한다.
Stack 영역
Heap영역과 반대로 먼저 들어온 데이터가 가장 높은 주소에 저장되고 점차 낮은 주소로 데이터가 쌓인다.
데이터가 소멸될때는 가장 낮은 주소의 데이터부터 소멸되며, 이것을 후입선출(LIFO)이라고 한다.
이때 컴파일타임에 Stack 영역이 Heap영역을 침범하거나 런타임에 Stack영역의 크기를 벗어나는 것이 Stack over flow 에러이다.
5. 의문
Heap영역을 선입선출, Stack영역을 후입선출로 비교하는 글들이 있다.
아직 메모리의 동작 과정을 이해하지 못해서인지 Heap영역은 low level에서 high level로 쌓이고 임의로 해제하는 순서대로 데이터가 소멸하는데 왜 Heap영역을 선입선출이라고 하는지 모르겠다.
그리고 직접 코드를 실행해보며 메모리를 확인해 보니 생각과는 다르게 데이터가 순차적으로 차곡차곡 쌓이지 않는다.
이 부분을 구글링 해봐도 다들 순서대로 쌓인다고만 적고 세부적인 내용은 찾기 힘들었다.
아직 지식에 부족한 부분이 있는 것 같아 조금 더 공부를 하고 해당 부분을 추가해야 될 것 같다.
04.10. 추가----
온라인 컴파일러로 확인해보니 생각했던대로 데이터가 쌓인다.
Visual C++의 차이일지도 모르겠다.
틀린 내용이 있다면 댓글로 적어주세요