리눅스데브코스 [10주차 - 4]<가상 메모리 개념>

심우열·2023년 6월 19일
0

1. 메모리 가상화의 필요성

1. 단일 프로그래밍 시스템

  • 하나의 프로세스만 동작

단점

  • 매 시점 하나의 프로그램만 동작하기 때문에 자원 낭비
  • 가상 메모리를 사용하지 않아 프로세스가 OS를 공격 할 수 있음

2. 멀티프로그래밍의 목표

1. 투명성

  • 프로세스는 메모리가 공유되는 것을 알지 못함
  • 프로세스의 수/위치에 무관하게 프로그래밍

2. 보호

  • 다른 프로세스나 OS의 메모리(데이터)를 읽거나 수정하지 못함

3. 효율성

  • 물리 메모리 자원의 낭비 방지(물리 메모리 단편화 등)

4. 공유

  • 상호 협력하는 프로세스간의 메모리 공유가 가능해야 함

3. 가상 주소 공간

  • Byte 단위의 주소로 접근되는 메모리 주소 공간

1. 주소 공간이란?

  • Code, Data, Stack, Heap등 프로세스가 동작하는데 사용하는 컴포넌트(segment)가 위치하는 주소 공간
  • 정적 컴포넌트: code, data(전역 변수)
  • 동적 컴포넌트: stack, heap

2. 목표

  • OS는 개별 프로세스에 자신만의 privata한 주소공간을 제공

2. 동적 메모리(컴포넌트)

1. 프로세스가 동적 메모리를 필요로 하는 이유

  • 프로그램 컴파일 시점에서는 얼마만큼의 메모리를 사용할지 알지 못함
  • 정적 메모리 할당은 최소한으로 이루어져야 함
    -> 최대 메모리 사용량만큼 할당하는 것은 메모리 낭비

2. 재귀적 함수(프로시저)

  • 프로시져가 얼만큼 호출될지 알 수 없음
  • 지역변수의 메모리 공간은 호출마다 할당됨

3. 복잡한(동적으로 할당되는) 데이터 구조들

  • linked list, tree 등등

3. 동적 메모리 할당 방법

1. stack

  • 함수 호출 시 지역변수는 stack 에 동적으로 할당
  • 함수 호출시 지역변수의 메모리가 할당됨
  • 함수 해제시 지역변수의 메모리가 해제됨

2. Heap

1. 임의의 시점에 임의의 크기의 메모리를 할당(malloc(), new())

  • Heap은 가상 메모리 내 공간으로, 할당된 메모리 영역, 해제된 메모리 영역(hole)이 있음.
  • 메모리 공간의 할당 해제는 임의의 순서이므로 예측 불가

2. 장점

  • 모든 종류의 data structure에 적용 가능

3. 단점

  • 할당 속도가 느림(stack은 expand, shrink만 하면 됨)
  • Heap 공간이 조각날 수 있음(external fragmentation)
  • 할당하는 메모리 공간 크기에 따른 내부 단편화(internal fragmentation)

4. Heap에 대한 OS의 역할

  • OS 는 heap 영역(큰 공간)만 제공하고, C lib에서 큰 공간을 쪼개서 malloc()/free()를 통해 서비스 함
  • OS는 brk() 시스템 콜을 통해 heap 영역의 사이즈를 지정해 제공

3. 예시

1. 코드

int x;
int main(int argc, char *argv[]){
	int y;
    int *x = malloc(sizeof(int));
}

2. 변수 별 메모리 공간

  • x : static data
  • main : code
  • y : stack
  • z : stack
  • *z : heap

4. 메모리 가상화의 방법

다수의 프로세스를 동시에 실행 가능하게 하기위해

  • 프로그램 바이너리 내에 메모리 주소는 고정되어 있음
  • 다수의 프로세스 사이에 메모리 충돌(같은 주소에 접근)을 해결해야 함

1. 시분할

1. 원리

  • 프로세스 별로 물리메모리 사용 가능 시간을 지정
  • 지정된 시간이 지나면 물리 메모리의 내용을 디스크로 옮김
  • 다른 프로세스를 물리메모리에 옮김

2. 문제점

  • 성능이 매우 떨어짐
  • 매번 프로세스의 메모리를 디스크와 물리메모리로 복사해야되기 때문

2. 정적 재배치

1. 원리

  • OS가 프로그램의 주소를 프로세스 생성 시점에 바꿔줌
  • 각 프로그램이 로딩되는 물리 메모리 위치에 기반하여 명령어에서 사용하는 주소를 번역

2. 단점

  • 다른 프로세스의 메모리를 보호해줄 수 없음
    -> 프로세스가 다른 프로세스나 OS의 메모리를 읽고 수정할 수 있기 때문
  • 프로세스의 위치를 변경할 수 없음
    -> 메모리가 부족할 경우 compaction 같은 작업이 쓰일 수 있으나 정적 재배치의 경우 불가능

3. 동적 재배치

1. 원리

  • 프로세스들 사이에 보호를 제공
  • CPU 하드웨어의 지원이 필요함
    -> MMU(Memory management unit)
  • MMU가 프로세스가 사용하는 주소를 매번 동적으로 재배치해줌
    -> 프로세스는 logical(virtual) 주소 사용
    -> 물리메모리에 접근할때는 physical(real) 주소 사용

2. 동적 재배치를 위해 CPU는 두개의 동작 모드 지원(execution mode)

1. 특권/커널/보호 모드

  • OS가 동작
  • 커널모드로 전환/OS의 핸들러 수행을 유발하는 구조 제공
  • 특권 권한의 명령어 수행 가능
  • 모든 물리 메모리 접근 가능

2. 유저 모드

  • 유저 프로세스 동작
  • MMU가 각 유저 프로세스의 가상 주소공간 및 그 내부에 가상 메모리 제공
  • OS 가 MMU에 설정한 만큼만의 메모리 접근 가능

3. 동적 재배치 기법

1. Base Register

  • 모든 메모리 주소는 MMU의 주소변환을 통과
  • 프로세스 생성 시 프로세스에 할당된 물리메모리의 시작 주소를 base로 설정
  • 컨텍스트 스위칭시마다 base register의 값을 현재 프로세스의 것으로 변경

문제점

  • 할당된 프로세스의 메모리 공간을 벗어날 수 있음

2. Base + Bounds Register

  • Bounds register를 추가해 허용된 범위만 접근 가능하게 해줌
    -> Base register: 주소공간의 물리메모리상 시작 주소
    -> Bounds register: 해당 프로세스의 주소공간의 크기
  • Bound의 크기를 벗어나는 logical address를 생성하는 경우 프로그램 종료 시킴
    -> Segmentation fault

3. Base + Bound 의 문제점

  • 동적 메모리에 대한 고려 부족
  • Heap 영역과 Stack 영역이 얼마나 커질지 알 수 없음
    -> 사용 안되는 공간의 낭비 발생
  • 프로세스간 메모리 공유가 불가능
  • 메모리별 접근권한 관리 불가능

4. 해결 방안

  • Segmentation
    ->Segment(stack, heap, code, data) 별로 base + bound
  • Paging

4. Segmentation

1. 프로세스의 공간을 다수의 segment로 구분

  • Code, heap, stack

2. 각 segment 별로 base + bound를 가짐

  • 각 segment 별로 독립적으로 expand/shrink 가능
  • segment 별로 접근 권한 관리 가능
  • segment 공유 가능
    -> 다른 프로세스들이 일부 segment에 같은 base + bound 사용

Segment table의 모습

profile
Dev Ops, "Git, Linux, Docker, Kubernetes, ansible, " .

0개의 댓글