[OS] 프로세스 메모리 구조
1. 주소 공간
1.1. CPU address space
- 물리 메모리 (주소) 라고도 한다.
- CPU Bus 크기1에 의해 결정된다.
- 32 bit CPU → 주소선 32개 → $2^{32}$ → 4GB
- 64 bit CPU → 주소선 64개 → $2^{64}$ → 16EB(=2,305,843.01TB)
- 주소 공간은 0번지부터 시작한다.
- 1개 번지의 저장공간 크기 $=$ 1바이트
- CPU 주소공간보다 큰 메모리 엑세스 불가능
- CPU 주소공간보다 작은 양의 메모리는 가능
- 예) 32비트 CPU 가진 컴퓨터에 2GB 메모리 설치되어 있을 때 → 2GB 넘어서 액세스하면 오류 발생
1.2. Process address space
- 프로세스가 실행되는 중 접근이 허용된 주소의 최대 범위 $=$ Segmentation
- 할당된 공간에 대한 경계 레지스터, 한계 레지스터 벗어나는지 감시 (CPU 관점)
그런데 프로세스는 자신이 CPU 주소 공간 전체를 독점하는 것처럼 보인다!
- ‘가상 메모리‘라는 개념이 적용되기 때문이다.
- 모든 프로세스는 자신만의 가상 주소 공간을 가진다.
- 32bit CPU에서 작동되는 프로세스는 논리적으로 4GB 메모리 할당받은 것처럼 보인다.(물리 메모리가 2GB더라도)
→ Logical memory vs Physical memory
- 프로세스 주소 공간은 두 부분(User space, Kernel space)으로 나누어진다.
1.2.1. User space(사용자 공간)
- 코드 영역
- 데이터 영역
- 힙 영역
- 스택 영역
1.2.2. Kernel space(커널 공간)
프로세스가 syscall 통해 이용하는 공간으로, 모든 사용자 프로세스에 의해 공유된다.
- 커널 코드
- 커널 데이터
- 커널 스택(커널 코드가 실행될 때)
2. 가상 메모리 사용 이유
- 메모리 확장성
- 물리적 메모리는 한정적이지만, 가상 메모리는 더 큰 공간으로 구성 가능
- 초과 분은 보조기억장치 등을 활용, 가상 주소 공간은 저장장치 구분 없이 하나의 가상 공간으로 활용이 가능하다. → Page swap 등 필요
- 모든 프로그램에 대한 동일한 메모리 공간 제공
- 각 프로세스는 다른 프로세스 신경 쓸 필요가 X
- 각 프로세스 간 Memory protection → 메모리 격리, 보호
RTOS 등 일부 OS는 가상 메모리 이용하지 않고 직접 접근하기도 한다.
3. 프로세스의 메모리 구조
프로세스가 메모리에 올라갈 때, OS는 특정한 구조로 메모리에 적재시킨다. 이때 영역을 구분하는데, 크게 네 부분으로 구분할 수 있다.
영역 | 할당되는 객체 | 크기 결정 시기 | 설명 |
---|---|---|---|
코드(code) 영역 | 프로그램 코드 | Compiled time | 사용자가 작성한 모든 함수/라이브러리 함수들의 코드 |
데이터(data) 영역 | 전역 변수(global) 정적 데이터(static) | Compiled time | rdata, data, bss 등으로 구분됨 사용자 프로그램, 라이브러리 포함 프로세스 적재시 할당, 종료시 소멸 |
힙(heap) 영역 | 실행중 동적 할당된 객체 | Runtime | malloc() 등으로 할당받는 공간은 힙 영역에서 할당됨힙 영역에서 아래 번지로 내려가면서 할당 |
스택(stack) 영역 | 함수 내 지역적인 객체 | Runtime | 매개변수, 지역변수, 함수 종료 후 돌아갈 주소 등이 저장됨 함수 호출 시, 스택 영역에서 위쪽으로 공간 할당 함수 return시 할당된 공간 반환함 |
이처럼 메모리 구조가 영역이 구분된 이유는 다음과 같다.
- 데이터를 공유하여 메모리 사용량을 줄이기 위함이다.
- 스택 구조와 전역 변수의 활용성을 위해서이다.
3.1. Code 영역이 구분된 이유
- 프로그램 코드는 컴파일되고 나서는 바뀔 일이 전혀 없음 → Read-Only
- 같은 프로세스가 여러 프로세스로서 실행될 때, 코드 영역을 공유(Share)함으로서 메모리 사용량 감소 가능
3.2. Data 영역이 구분된 이유
- 전역변수/정적(static)변수 저장 영역 → Read-Write (참고: 리터럴(literal)들은 read-only)
- 전역/정적변수 → 프로그램 실행되는 동안 항상 접근 가능해야 함 → 프로그램 실행과 관계 없이 독립적 영역이 필요하다.
3.3. Heap 영역이 구분된 이유
- 프로그램 실행 도중 필요시마다 할당받는 공간 → 얼마나 필요할 지 예측 불가
3.4. Stack 영역이 구분된 이유
- 프로그램은 함수의 호출로 이뤄짐(함수는 프로그램의 실행 단위)
- 지역변수, 매개변수, 반환 값 등이 존재함
- 스택 구조 이용하면 함수 호출 순서/반환 대상 등 관리가 편해진다
- Callstack: 스택 프레임을 통한 함수의 실행 순서 구분
3.5. Heap, Stack이 자라나는 방향이 다른 이유
- Heap, Stack은 실행 상태에 따라 얼마나 사용될지 모름
- 동적 공간에서 서로 공간을 유용하게 활용하기 위해서이다.
4. 프로세스 주소 → 물리 주소 변환
가상 메모리에서 다시 등장하는 개념이다.
각주
이를 1 Word라 하며, CPU 아키텍쳐 크기(32 bit, 64 bit 등)와 같다. ↩
이 포스팅은 작성자의 CC BY-NC 4.0 라이선스를 준수합니다.