프로그램이 실행 될 때 우리가 알기도 전에 메모리가 할당 됩니다. 변수 하나를 만들 때 마다 프로그램은 변수를 저장하기 위해 메모리를 할당합니다. 이번 글에는 프로세스 메모리에서 가장 큰 역할을 차지하는 Stack과 Heap에 대해서 집중해 보겠습니다.
일반적인 프로세스의 구조는 다음과 같다.

프로세스는 각자 자기의 공간을 메모리에 가지고 있고 메모리에는 모든 프로그램의 코드와 변수, 다른 모든 allocated storage가 저장된다.
이 자료는 프로세스의 여러 부분 중 메모리에 관해서 이야기해보겠다.

메모리 아케텍쳐를 보면 크게 4가지 영역으로 나눌 수 있다.
BSS는 초기화가 안된 전역 변수를 저장하는 영역으로 많은 자료들에서 Data에 합쳐서 개념을 설명한다.
각각의 메모리의 "주소" 바이트를 할당하고 운영체제에 따라 0부터 시작하여 할당 가능한 주소를 찾는다. text,data 그리고 heap은 low address numers 즉, 낮은 주소 부터 채워지고 stack은 higher addresses를 가진다.
컨벤션에 따라 주소는 16진수 숫자로 표현되며 0x00000000부터 0xFFFFFFFF(0x의 의미는 16진수)까지 가질 수 있다.
사진에서 보다시피 stack segment는 메모리의 위에 즉, 가장 높은 주소에 위치한다. 함수가 호출될 때 마다, OS는 stack에 메모리를 할당한다. 새로운 지역 변수가 선언되면 함수의 변수를 저장하기 위해 더 많은 스택 메모리를 아래 방향으로 할당하게 된다. 함수 리턴 이후에 해당 함수, 모든 지역 변수가 스택에서 빠지게 된다. 스택 메모리에서의 할당과 해제는 모두 자동적으로 진행된다.
다음 그림은 일련의 과정을 모식화 한 것이다.

함수의 스택 메모리가 해제된 이후로 해당 영역이 똑같은 형태로 유지됨을 보장 할 수 없다. 가장 흔한 실수 중 하나는 함수 변수를 포인터로 탐아서 부모 함수로 리턴하는 것이다. 부모 함수가 포인터를 받으면 유효하지 않은 스택 메모리에 언제든 덮어쓰기 할 수 있다.

쉽게 예를 들이, Cube 클래스가 getVolum, getSurfaceArea, private width를 가지고 있고, CreateCube가 객체를 생성한다고 가정하자.
main에서 CreateCube를 호출하고 Cube객체를 생성 후 주소를 리턴한다. 리턴이 되면서 해당 객체는 해제되고 메인에서 c->getVolume을 호출하면 유효하지 않은 즉, 의도하지 않은 영역을 read하게 되는 상황이다.
앞선 문제에서 함수는 스택 변수는 포인터를 return하지 못 하는 문제를 보았다. 이러한 문제를 해결하기 위해 값을 리턴하거나 값을 스택 메모리가 아닌 다른 곳에 저장하는 방법이 있다. 힙 메모리가 그러한 영역이다. 스택과 다르게 힙은 프로그래머에 의해 명시적으로 할당되고 명시적으로 해제하기 전까지 해제되지 않는다. 그 뜻은 프로그래머의 역량에 따라서 메모리 사용률이 매우 차이가 날 수 있다. 사용하지 않는 메모리를 해제하지 않는 것을 leak(누수)라고 한다. 메모리 누수는 작은 프로그램에겐 큰 일처럼 보이지 않을 수 있지만 오래 실행되는 서버에서는 누수가 느려짐과 충돌을 야기할 수 있다.
다음 그림은 Heap 할당을 모식화 한 것이다.

해제를 하고 나서 해제한 메모리를 참고하는 포인터를 사용하는 것은 undefined behavior를 야기한다. 이러한 실수를 줄이기 위해서 해제한 포인터를 해제 하자마자 nullptr로 초기호하는 좋은 습관을 들여야한다.
Elements of a process
Stack and Heap Memory
Process (computing) Wiki
How Memory Allocation Works on Linux