Skip to content

메모리 구조 (프로세스 메모리 레이아웃) ​

프로그램을 실행하면 운영체제가 그 프로세스만 쓰는 메모리 공간을 하나 내어 줍니다. 이것을 프로세스 주소 공간이라고 하고, 안쪽은 하는 일에 따라 Text(Code), Data, BSS, Heap, Stack 영역으로 나뉩니다.

비유: 아파트 층별 구조 ​

프로세스가 사용하는 메모리를 아파트라고 생각해보세요. 각 층마다 역할이 다릅니다.

높은 주소
┌─────────────────────────┐
│         Stack           │ ← 5층: 함수 호출 기록, 지역변수
│    (아래로 성장 ↓)       │   (자동 관리 - 함수 끝나면 사라짐)
├─────────────────────────┤
│           ↕             │ ← 빈 공간 (Stack ↔ Heap이 서로 마주보며 성장)
├─────────────────────────┤
│          Heap           │ ← 4층: 동적 할당 공간 **누수 발생 지점!**
│    (위로 성장 ↑)         │   (수동 관리 - 개발자가 직접 해제해야 함)
├─────────────────────────┤
│          BSS            │ ← 3층: 초기화 안 된 전역변수
├─────────────────────────┤
│          Data           │ ← 2층: 초기화된 전역변수
├─────────────────────────┤
│          Text           │ ← 1층: 실행 코드 자체
└─────────────────────────┘
낮은 주소

이 문서의 누수는 4층(Heap)에서 발생! 짐을 계속 쌓기만 하고 치우지 않아서 아파트가 꽉 찬 상황

영역별로 자세히 보기 ​

영역무엇이 들어가나크기가 정해지는 때특징
Text (Code)실행할 기계어 명령어컴파일할 때읽기 전용. 같은 프로그램을 여러 개 띄우면 이 영역을 함께 쓸 수 있음
Data초깃값이 있는 전역 변수, static 변수컴파일할 때프로그램이 끝날 때까지 남아 있음
BSS초깃값이 없는 전역 변수, static 변수컴파일할 때실행할 때 0으로 채워짐
Heapmalloc, new, 파이썬 객체처럼 실행 중에 만드는 데이터실행할 때개발자(또는 GC)가 직접 정리해야 함. 높은 주소 쪽으로 자람
Stack함수 매개변수, 지역 변수, 돌아갈 주소실행할 때함수가 끝나면 자동으로 사라짐. 낮은 주소 쪽으로 자람
  • Heap과 Stack은 빈 공간을 사이에 두고 서로 마주 보며 자랍니다. 함수를 너무 깊게 부르면(예: 끝나지 않는 재귀) Stack이 정해진 크기를 넘어서 스택 오버플로가 나고, Heap을 쓰고 치우지 않으면 메모리 누수가 생깁니다.

왜 이렇게 영역을 나눌까 ​

핵심은 함께 쓸 수 있는 것은 함께 써서 메모리를 아끼고, 성격이 다른 데이터는 관리 방식을 다르게 하기 위해서입니다.

  • Code를 따로 두는 이유: 같은 프로그램이면 명령어 내용이 모두 똑같습니다. 크롬 창을 여러 개 띄워도 코드는 한 벌만 메모리에 두고 함께 읽으면 됩니다. 그래서 읽기 전용으로 따로 관리합니다.
  • Stack과 Data를 나누는 이유: 함수와 지역 변수는 "나중에 부른 함수가 먼저 끝나는" 순서(LIFO)로 생기고 사라지므로 스택 구조가 딱 맞습니다. 반면 여러 함수가 같이 쓰는 전역 변수는 함수가 끝나도 남아 있어야 하므로, 스택이 아닌 Data 영역에 한 번만 두고 모두가 참조하게 하면 메모리를 아낄 수 있습니다.
  • Heap을 따로 두는 이유: 크기를 실행해 봐야 아는 데이터(예: 사용자가 올린 파일 개수)는 미리 자리를 잡을 수 없습니다. 필요할 때 빌리고 다 쓰면 돌려주는 공간이 따로 필요합니다.

스레드는 어떤 영역을 함께 쓸까 ​

한 프로세스 안의 스레드들은 Stack만 각자 따로 갖고, Text, Data, BSS, Heap은 함께 씁니다. 각 스레드가 서로 다른 함수를 동시에 실행하려면 함수 호출 기록(Stack)은 따로 있어야 하기 때문입니다. 자세한 내용은 프로세스와 스레드를 참고하세요.

text
프로세스 하나
┌─────────────────────────────────────┐
│ Text │ Data │ BSS │ Heap  ← 모두 공유 │
├─────────────────────────────────────┤
│ Stack(스레드1) │ Stack(스레드2) │ ... │ ← 스레드마다 따로
└─────────────────────────────────────┘

정리 ​

영역역할관리 · 크기
Stack함수 호출 기록, 지역변수 (아래로 성장)자동 (함수 끝나면 사라짐)
Heap동적 할당 공간 (위로 성장), 누수 발생 지점수동 (개발자가 직접 해제)
BSS초기화 안 된 전역변수 (실행 시 0으로 채움)컴파일 때 고정
Data초기화된 전역변수, static 변수컴파일 때 고정
Text실행 코드 자체, 읽기 전용이라 같은 프로그램끼리 공유 가능컴파일 때 고정
스레드Stack만 따로, 나머지 영역은 같은 프로세스의 스레드끼리 공유

출처: Codyssey-B1/B4-2