프로세스 메모리 (Swift의 heap은?)

2024. 6. 15. 14:15·CS

초기 컴퓨터의 한계와 문제점

초기 컴퓨터 시스템을 보면 정말 단순했습니다.

한 번에 하나의 프로세스만 실행할 수 있었고, 메모리도 물리적으로 직접 할당하는 방식이었죠.

그런데 이 방식에는 치명적인 문제가 있었습니다. 🤔

 

단일 프로세스 실행의 한계

타임셰어링 환경이 등장하면서 여러 사용자가 동시에 컴퓨터를 사용하려는 요구가 생겼는데,

기존 방식으로는 이를 전혀 충족할 수 없었습니다. 한 사용자가 프로그램을 실행하면 다른 사용자는 그냥 기다려야 했거든요.

 

메모리 활용의 비효율성

물리 메모리에 프로세스를 직접 할당하다 보니까, 메모리 공간이 심하게 낭비되는 경우가 많았습니다.

예를 들어 1MB 프로세스를 위해 2MB 영역을 할당하면 1MB는 그냥 버려지는 식이었죠.

이 문제를 해결하기 위해 메모리를 동일한 크기의 파티션으로 나누는 방식이 나왔지만,

멀티프로그래밍 시대가 되면서 더 근본적인 문제들이 드러났습니다.

Protection과 Relocation의 필요성

멀티프로그래밍이 본격화되면서 두 가지 핵심 문제가 부각되었습니다.

 

Protection (보호)

각 프로세스가 서로의 메모리 공간을 침범하지 않도록 보장하는 메커니즘이 필요했습니다.

더 중요한 건 운영체제 자체의 메모리 공간도 보호해야 한다는 점이었죠.

생각해보세요. 사용자 프로세스가 실수로든 악의로든 운영체제의 핵심 데이터를 건드린다면?

시스템이 완전히 먹통이 될 수 있습니다. 😱

 

Relocation (재배치)

이게 정말 흥미로운 문제인데요, "프로그램이 메모리 어디에 올라가야 하는데!" 라는 근본적인 질문에서 시작됩니다.

멀티프로그래밍 환경에서는 프로세스가 메모리의 어느 위치에 적재될지 실행 전에 알 수 없습니다

. 동일한 프로그램이라도 실행할 때마다 다른 물리 메모리 위치에 올라갈 수 있거든요.

 

그럼 프로그램은 어떻게 자신의 메모리 주소를 참조해야 할까요? 🤔

이 문제를 해결하기 위해 동적 재배치라는 개념이 등장했습니다.

프로그램은 항상 동일한 메모리 주소(보통 0번지)에서 시작한다고 가정하고, 실행 시점에 이를 실제 물리 주소로 변환하는 방식이죠.

가상 메모리의 등장과 핵심 개념

위의 모든 문제를 한 방에 해결한 게 바로 가상 메모리입니다. 이 개념이 정말 혁신적인 이유는 물리 메모리와 논리 메모리를 완전히 분리했다는 점입니다.

주소 공간 분리: 논리적 주소 vs 물리적 주소

각 프로세스는 독립적인 논리적 주소 공간을 가지게 됩니다.

이는 실제 물리적 주소와 완전히 분리되어 있어서, 프로세스 입장에서는 자신만의 메모리 공간을 독점하는 것처럼 느껴집니다.

투명한 재배치

프로그램은 항상 0번지부터 시작한다고 가정할 수 있게 되었습니다.

실제 물리 메모리 위치는 실행 시점에 동적으로 매핑되니까요. 이렇게 해서 Relocation 문제가 완전히 해결되었습니다.

동적 매핑

실행 시간에 논리 주소를 물리 주소로 변환하는 과정이 투명하게 처리됩니다.

개발자나 프로그램은 이 과정을 전혀 의식할 필요가 없어졌죠.

 

가상 메모리의 주요 특징들:

  1. 프로세스별 독립 주소 공간 - 각자만의 메모리 세상을 가짐
  2. 아키텍처별 가상 메모리 크기 - M1에서는 ARM64 아키텍처를 사용해서 이론상 16엑사바이트(EB)까지 가능하지만, 실제로는 MMU 설계나 SoC 제한으로 전체를 다 쓰지는 않습니다

MMU와 주소 변환 과정

MMU(Memory Management Unit)는 논리적 주소를 물리적 주소로 변환하는 핵심 역할을 하는 하드웨어입니다.

프로그램의 메모리 접근 과정:
1. 프로그램: "0x1000번지 데이터 읽어줘"
2. MMU: "0x1000은 실제로는 0x5000이야"
3. RAM: 0x5000에서 데이터 반환

이 과정이 신기한 게, 프로그램은 자신이 0x1000에 접근한다고 생각하지만 실제로는 완전히 다른 물리 주소에 접근하고 있다는 점입니다. 

MMU의 주요 기능:

  1. 주소 변환 - 페이지 테이블을 참조해서 가상→ 물리 주소 변환
  2. 메모리 보호 - 권한을 확인해서 불법 접근을 차단

저는 처음에 MMU가 소프트웨어인 줄 알았는데, 실제로는 CPU에 내장된 하드웨어더라고요.

그래서 주소 변환이 이렇게 빠르게 처리될 수 있는 거였습니다.

메모리 레이아웃 완전 분석

TEXT 영역 (Code Segment)

int main() {           // ← 이 함수의 기계어 코드가 TEXT 영역에 저장
    return 0;
}
  • 목적: 실행 가능한 기계어 코드 저장
  • 권한: 읽기 + 실행 (r-x), 쓰기 불가
  • 크기: 컴파일 시 결정되어 실행 중 변경 불가
  • 공유: 같은 프로그램의 여러 인스턴스가 공유 가능

TEXT 영역이 읽기 전용인 이유가 뭘까요? 🤔

프로그램 코드가 실행 중에 변경되면 예측 불가능한 동작이 발생할 수 있기 때문입니다. 보안상으로도 중요한 보호 메커니즘이죠.

DATA 영역

int global_var = 100;      // ← DATA 영역에 저장
static int static_var = 50; // ← DATA 영역에 저장
  • 목적: 초기화된 전역 변수와 정적 변수 저장
  • 권한: 읽기 + 쓰기 (rw-)
  • 크기: 컴파일 시 결정
  • 특징: 프로그램 시작 시부터 메모리에 존재

BSS 영역 (Block Started by Symbol)

int uninitialized_global;      // ← BSS 영역에 저장 (자동으로 0)
static int uninitialized_static; // ← BSS 영역에 저장 (자동으로 0)
  • 목적: 초기화되지 않은 전역 변수와 정적 변수
  • 권한: 읽기 + 쓰기 (rw-)
  • 특징: 자동으로 0으로 초기화됨
  • 최적화: 실제로는 0으로 채워지지 않고, 접근 시 0을 반환

BSS 영역의 최적화 방식이 정말 영리하다고 생각해요. 메모리를 실제로 0으로 채우지 않고도 0을 보장할 수 있거든요.

HEAP 영역

int* ptr = malloc(sizeof(int) * 100); // ← HEAP 영역에 할당
free(ptr);                            // ← 직접 해제해야 함
  • 목적: 프로그램 실행 중 동적으로 할당되는 메모리
  • 권한: 읽기 + 쓰기 (rw-)
  • 크기: 실행 중 동적으로 변경 가능
  • 성장 방향: 낮은 주소에서 높은 주소로 (위쪽으로)
  • 관리: 프로그래머가 직접 관리 (malloc/free, new/delete 등)

STACK 영역

void function() {
    int local_var = 10;    // ← STACK 영역에 저장
    char array[100];       // ← STACK 영역에 저장
    // 함수 종료 시 자동으로 해제됨
}
  • 목적: 함수 호출 시 생성되는 지역 변수, 매개변수, 반환 주소
  • 권한: 읽기 + 쓰기 (rw-)
  • 크기: 보통 8MB로 제한 (시스템마다 다름)
  • 성장 방향: 높은 주소에서 낮은 주소로 (아래쪽으로)
  • 관리: 함수 호출/반환에 따라 자동으로 생성/제거

스택과 힙이 서로 반대 방향으로 성장하는 것도 재미있는 설계입니다. 이렇게 해야 서로 충돌할 가능성을 최소화할 수 있거든요. 😊

Apple 빌드 과정에서 가상메모리는 어떻게 할당될까??

1. 앱 시작시 자체적인 빈 가상 메모리 주소 공간을 할당 받고

2. 앱이 실행되면 메인 실행 파일과 연결된 (정적, 동적) 라이브러리가 할당되고

3. 디스크에서 read-only 메모리 할당, 리소스 영역 매핑해서

4. 마지막으로 힙과 스택 영역이 할당이 됩니다.

또한 힙 메모리를 보면 

힙은 하나의 메모리블록이 아니라 multiple한 가상 메모리 영역으로 구성되어 있습니다. 

각 영역들은 개별  할당으로 구분되고 내부적으로 16KB메모리 페이지로 구성되어있습니다.

총 3가지 상태가 있는데, 아직 기록되어있지 않은 Clean,

앱이 최근에 쓴 메모리인 Dirty(그래서 한동안 사용되지 않을때도 버릴수가 없다. 즉 page out 이 불가!),

Swapped 영역은 메모리 부족이 있을때, 시스템이 메모리를 압축하거나 디스크에 기록하여 교체합니다.

이 중 swapped, dirty만이 앱의 메모리공간을 차지하고 대부분의 앱에서 힙은 이 두공간으로 이루어집니다

그러면 힙에는 모가 저장되는데?

그냥 예상답변으로는 class, reference type이 하겟지? 

그러면 struct는 절대 힙에 저장이 안되나요? nono 만약 struct안에 class인스턴스가 존재한다면?

그 전에 Swapped와 dirty를 좀더 자세히 이해하기 위해서는 Compressed Memory를 알아야합니다~.  

아 그런데 그전에 더 기초적인 페이지 개념을 공부 한후에 설명을 이어가보도록 하겠씁니다!

메모리페이징과 압박 상황

페이지 (Page)의 개념

메모리를 관리하는 기본 단위가 페이지입니다. 일반적으로 4KB 크기를 사용하지만, macOS에서는 16KB 페이지를 사용합니다.

왜 Apple이 더 큰 페이지 크기를 선택했을까요? 🤔

페이지 크기가 클수록 페이지 테이블 크기가 작아지고, TLB(Translation Lookaside Buffer) 미스가 줄어들어 성능이 향상되기 때문입니다.

페이징의 장점들

  1. 메모리 단편화 해결 - 고정 크기 단위로 관리해서 외부 단편화 문제 해결
  2. 가상 메모리 구현 - 물리 메모리보다 큰 가상 주소 공간 가능
  3. 메모리 보호 - 페이지별로 세밀한 권한 설정 가능
  4. 스왑 메모리 - 사용하지 않는 페이지를 디스크로 이동 가능

페이지 테이블의 동작

가상 페이지 번호 → 물리 페이지 번호
       0       →       15
       1       →       23
       2       →       8
       ...

이 매핑 테이블이 바로 가상 메모리의 핵심입니다. 프로세스마다 독립적인 페이지 테이블을 가지고 있어서, 같은 가상 주소라도 다른 물리 주소로 매핑될 수 있습니다.엡 시작시 자체적인 빈 가상 메모리 주소 공간을 할당 받음


메모리 압박과 스왑

메모리 압박 상황이 발생하는 경우:

  1. 물리 메모리 부족 - 실행 중인 프로세스들의 메모리 사용량이 물리 RAM 초과
  2. 페이지 아웃(Page Out) - 사용하지 않는 페이지를 디스크로 이동
  3. 페이지 인(Page In) - 디스크의 페이지를 다시 RAM으로 로드

Apple의 특화된 메모리 관리

일반적인 운영체제와 달리, Apple은 독특한 메모리 압축 방식을 사용합니다.


Compressed Memory

일반적인 시스템: RAM → 디스크 스왑
Apple 시스템: RAM → 메모리 압축 → 디스크 스왑

Apple은 메모리가 부족해지면 바로 디스크로 스왑하지 않고, 먼저 메모리를 압축해서 더 많은 데이터를 RAM에 유지하려고 합니다.

압축 메모리의 장점들:

  • 디스크 I/O 오버헤드 제거 - 디스크 접근을 최대한 피함
  • 2:1 ~ 4:1 압축률 - 메모리 효율성이 크게 향상됨
  • 배터리 수명 개선 - 모바일 기기에서 중요한 요소
  • SSD 수명 연장 - 쓰기 횟수를 줄여서 SSD 수명을 늘림

iOS 같은 모바일 디바이스에서는 대부분의 데이터가 휘발성이라 디스크에 큰 의미가 없습니다

마침 CPU 성능도 엄청나게 발전했기 때문에 Compressed Memory 방식을 통해 RAM을 더 효율적으로 활용할 수 있게 된 거죠.

메모리의 read/write 속도가 CPU 클럭 속도를 여전히 못 따라오는 불균형 문제도 이 방식으로 어느 정도 극복할 수 있습니다. 🚀

그렇다면 생긴 의문점들 

1. 메모리 압축은 어떻게 하는데?

Wkdm알고리즘을 사용합니다.

32 bit data 16개로 이루어진 디렉토리와 압축된 결과를 쓸 메모리 공간만 있으면 압축할 대상의 크기에 상관없이 압축을 할 수 있다고 합니다. 압축할 데이터를 한번만 읽어 들이면 되어 적은메모리를 사용하여 빠르게 수행할 수 있어지는거죠

2. 압축할 페이지는 어떻게 정하는데? 

LRU(Least Recently Used) 가장 오래전에 사용된 순서로 정합니다.

3. 얼마나 압축을 할건데? 또 압축하는데 시간이 디스크 접근보다 얼마나 빠른데?

Wkdm알고리즘은 50%이상 압축을 한다고 한다. 페이징 스와핑보다 빨라야하잖아... 지직거리는 것을 없애려면,,,.

애플에서 준 자료에 따르면 4KB 페이지 하나 압축하는데 수백만분의 수초라고 하네요


 

 

https://www.youtube.com/watch?v=X_JYRz-Hd0o

 

 

 

 

 

'CS' 카테고리의 다른 글

파일 시스템  (4) 2025.07.22
Process Management와 System Call(커널 헷갈리는 개념 정리)  (2) 2025.07.22
'CS' 카테고리의 다른 글
  • 파일 시스템
  • Process Management와 System Call(커널 헷갈리는 개념 정리)
2료일
2료일
좌충우돌 모든것을 다 정리하려고 노력하는 J가 되려고 하는 세미개발자의 블로그입니다. 편하게 보고 가세요
  • 2료일
    GPT에게서 살아남기
    2료일
  • 전체
    오늘
    어제
    • 분류 전체보기 (133)
      • SWIFT개발일지 (28)
        • ARkit (1)
        • Vapor-Server with swift (3)
        • UIkit (2)
      • 알고리즘 (25)
      • Design (6)
      • iOS (42)
        • 반응형프로그래밍 (12)
      • 디자인패턴 (6)
      • CS (3)
      • 도서관 (2)
  • 최근 글

  • hELLO· Designed By정상우.v4.10.5
2료일
프로세스 메모리 (Swift의 heap은?)
상단으로

티스토리툴바