[운영체제] 메모리 관리1

ryun·2023년 4월 18일

운영체제

목록 보기
11/16

메모리

주소를 통해 접근하는 장치

메모리 주소 2종류

  • 로지컬 어드레스
    • 논리적 주소
  • 피지컬 어드레스
    • 물리적 주소

  • 물리적 메모리
    • 물리적 주소 0번지부터 시작
    • 낮은 주소는 운영체제 높은 주소는 여러 프로세스들
      • 사용자 프로그램은 디스크 실행파일에서 메모리에 올라가서 프로세스가 되는 것
      • 여기서 한 단계를 더 거치는데
        프로그램만의 독자적 메모리 주소 공간(논리적 주소 또는 가상 주소)을 거친다

  • 프로그래머는 숫자로된 주소가 아니라 심볼로 된 주소를 가지고 프로그래밍한다
    심볼링 어드레스가 컴파일되면 독자적 메모리주소가 매겨지고,
    메모리에 올라가서 실행이 되면 물리적 메모리 주소를 가지게 된다
  • 이 과정에서 주소 변환이 이루어진다

주소 바인딩

논리적 주소를 물리적 주소로 맵핑하는 과정
이 시점이 언제일까?

  • 설명

    • 왼쪽 A와 B의 값을 더해서 A에 저장 후 C의 위치로 점프를 해라
      A와 B는 A에 저장되어있고 B는 330 이제 A의 값은 430
    • 심볼릭 코드를 컴파일해서 만든 것이 로지컬 주소(논리적 주소)이고, 논리적 주소가 물리적 메모리에 올라간다
    • cpu는 기계어를 실행하고 기계어를 실행하려면 안의 메모리 주소를 그때그때 주소 변환을 해서 접근
      • jump 40은 40번지로 점프하라는 말
        40번지가 물리적 메모리 몇 번째지? 물리적 메모리에서 540번지라고 치면(사진엔 없음) 540번지로 점프
    • 기계어 자체를 수행할 때의 주소가 주소변환이 필요한 것
  • 컴파일 타임 바인딩

    • 컴파일 하는 시점에 물리적 주소가 결정된다
    • 논리적 주소 자체가 물리적 주소기 때문에 주소 변환이 필요없다
    • 내가 만든 프로그램을 메모리에 올릴 때, 항상 물리적 메모리 0번지부터 올라간다 => 대단히 비효율적
    • 컴파일 바인딩에 의해서 만들어진 코드가 앱솔루트 코드
      • 주소 변환이 필요없고 그대로 메모리에 올려서 실행시키면 된다
      • 바꾸고 싶으면 컴파일 다시해야한다
  • 로드 타임 바인딩

    • 프로그램 실행시키는 시점에 가상 메모리 주소가 물리적 메모리 주소로 바뀐다
      • 프로그램 시작 시에 메모리 위치가 바로 결정된다
      • 0번지부터 시작하는 프로그램이 500번지부터 시작
    • 여러 프로그램이 멀티태스킹 되는 현대 운영체제에서는 로드 타임 바인딩처럼 실행될 때 결정이 되는 방식이 타당
  • 런타임 바인딩

    • 프로그램 실행 도중에도 물리적 메모리 위치가 바뀔 수 있다
      • 실행도중에 300번지가 700번지로 변경될 수 있다
    • cpu가 메모리 접근할 때마다 런타임 바인딩에서는 바인딩을 점검해야한다 (바뀔 수 있기 때문)
  • 차이점

    • 컴파일로부터 미리 정해진 코드인지 아니면 나중에 재배치가 가능한 코드인지가 가장 큰 차이점
  • 주소변환은 하드웨어적 지원이 필요
    메모리 주소를 변환하는 일은 운영체제가 아니라 하드웨어가 하는 일이다
    메모리 접근은 사용자 프로그램 본인이 cpu를 통해 일을 하는건데, 메모리 하나 접근하려고 운영체제로 넘어가는 것은 상식적이지 않다
    메모리 접근을 할 때는 빨리 주소 변환이 이루어져야 하기 때문에
    하드웨어가 곧바로 주소변환해서 메모리에 접근한다
    *런타임 바인딩 경우는 매번 주소 변환을 해야되기 때문에 하드웨어적 지원이 필요하다

MMU

주소 변환 하는 하드웨어

간단한 주소 변환 방식은 아래와 같이 이루어진다

*프로그램에 논리적 주소가 있고, 물리적 메모리로 올라갈 때 묶여서 올라가는 상황을 전제로 설명한다

  • 해석
    오른쪽이 물리적 메모리
    왼쪽 점선이 한 프로그램의 가상 메모리
    프로그램이 실행되면서 cpu가 346번지 내용을 요청한다
    이것은 물리적 메모리의 14000번지부터 올라가 있다
    14000번지부터 17000번지까지 물리적 메모리가 위치해 있고
    시작위치에서 346을 더하면 요청한 메모리 주소가 나온다

  • 주소변환 하드웨어의 레지스터 두 개

    • relocation register(=base register)
      물리적 메모리의 시작 위치 담고 있다

    • limit register
      논리적 주소의 범위로 프로그램의 크기를 담고있다
      CPU가 요청한 논리주소가 리밋 레지스터보다 크다면 차단한다
      만약 프로그램이 악의적이라 3천이 리밋인데 5천을 달라는 기계어가 있다면
      14000에 5천 더했을 때 범위를 넘어가기 때문에 밖 주소공간에 접근하려는 악의적인 시도라고 판단


CPU가 로지컬 어드레스를 줄 때,
먼저 MMU는 그 레지스터가 리밋보다 작은지 체크한다
만족하면 주소를 변환히고
아니라면 트랩을 발생시킨다

  • 트랩
    • 소프트웨어어 인터럽트 > 다음 인스트럭션 실행하기 전에 cpu가 운영체제로 넘어간다
    • 운영체제는 악의적 메모리 접근하는 프로그램을 종료시키고,
      정상이라면 시작위치에 더해서 메모리에 접근한다

다이나믹 로딩

  • 프로그램을 구성하는 프로세스 주소 공간이 불릴 때 메모리에 그때그때 동적으로 올리는 것
  • 장점은 메모리 유틸라이제이션이 좋아진다는 것
    프로그램 안에 예외적 상황을 처리하는 코드들이 많은데 이런것까지 올려놓으면 메모리 낭비가 된다
    당장 필요한 실행되는 부분만 올려놓아서 사용률이 좋아진다
  • 다이나믹 로딩은 운영체제 특별한 지원 없이 프로그램 자체에서 구현 가능
    현대적 OS에서 하는 방식은 엄밀히 다이나믹 로딩 아니다 > 운영체제 지원 없이 프로그램 자체에서 라이브러리 통해 구현
    오리지널 다이나믹 로딩은 운영체제 지원 없이 라이브러리 통해 하는 것을 원래 의미했었다

오버레이

  • 실제 필요한 부분만 그때그때 메모리에 올린다는 의미
    (다이나믹 로딩과 의미가 같다)
  • 초창기에는 물리적 메모리 크기가 작아서 프로그래머가 수작업으로 메모리에 올리고 내리고를 프로그래밍 하는 것 > 오버레이
    • 메모리가 작던 시절의 이야기

스와핑

  • 프로그램을 메모리에서 통째로 쫓아내는 것
    • 어디로? 디스크 스토리지
  • 왼쪽이 물리적 메모리 오른쪽이 backing 스토리지
    워드 프로세서라는 프로그램이 메모리에 있다가 스왑아웃이 되면 통째로 쫓겨난다
    웹브라우저라는 프로그램이 쫓겨나있다가 스왑인이 되면 물리적 메모리에 다시 올라간다
  • 스와핑에서 사용되는 쫓겨나는 영역은 swap area(backing store)

중기 스케줄러(메모리에 너무많은 프로그램이 동시에 올라가잇으면 비효율적이라 일부 프로세스를 통째로 쫓아내는 것, 쫓겨나는 경우에 상태는 서스펜디드)에서 스왑아웃 된다면 서스펜디드
스완인되면 레디나 블럭과 같은 액티브한 상태로 올라간다

어떤 프로세스를 쫓아내는가?
CPU 우선순위가 낮은 프로세스
CPU에서 실행될 가능성이 낮은 것을 최우선 타겟으로 쫓아낸다

  • 바인딩
    • 컴파일이나 로드타임 바인딩에서는 스와핑이 지원되는데 제한 사항이 있다
    • 스왑아웃시키면 그 부분은 비어있게 된다
      다시 메모리에 올리고싶을 때, 다른 메모리 부분이 비어있어도 500에 올려야 한다 (주소가 바뀌면 안됨)
      원래 메모리 위치 고집하는 것 > 비효율적
    • 스와핑이 빈 메모리 공간을 잘 사용할려면 런타임 바인딩이 지원되어야 한다
      런타임 바인딩에서는 300에서 스왑아웃 되었다가 이후 메모리에 여유가 생겨서 700번지가 생기면 거기에 올려도 된다 > 빈 메모리 어디든지 효율적으로 사용

위에서 B가 스왑아웃된 상황?

  • 오리지널 스와핑에서 스왑아웃은 통째로 쫓겨날 때 스왑아웃 된 것
  • B는 조각 중 2개는 물리적 메모리에 있고 하나만 쫓겨난 상황
    • 일부 페이지만 쫓겨난 것이기 때문에 현대적 운영체제에서는 한 페이지만 스왑아웃 됐다고 말하기도 한다

다이나믹 링킹


프로그램 하나를 만들면 컴파일 되고 링킹이 되어서 실행파일이 만들어진다
링킹은 실행하기 이전에 작성한 프로그램이 사용하는 다른 프로그램이나 라이브러리를 가져와 연결하는 과정
링킹이 언제되는가?

  • 스태틱 링킹

    • 내가 만든 코드 + 라이브러리
    • 내가 만들지 않은 라이브러리가 컴파일 하고 나면 내 코드 안에 포함되는 것
  • 다이나믹 링킹

    • 라이브러리가 내 실행파일에 존재하지 않고 별도 파일 형태로 존재
    • 필요할 때 라이브러리를 파일 형태로 찾아서 메모리에 올리고 연결해서 실행시키는 것
    • 라이브러리 위치정보만 포함되어 있음
      * 리눅스 환경에서는 쉐어드 오브젝트가 .so로 끝난다
      윈도우즈 환경에서는 .dll
  • 특징

    • 스태틱은 함수를 프로그램에 각각 사용해서 컴파일 하면 각각의 프로그램 안에 들어가있다
      각 주소공간에 함수가 개별적으로 다 들어가 있다
    • 다이나믹 링킹 쉐어드 라이브러리로 구현되어있으면 실행파일 안에 없고 어떤 파일에서 찾을 수 있다고만 적혀져 있다
    • 불리는 순간 쉐어드 라이브러리를 메모리에 올려서 실행
    • 다른 프로그램이 호출하는 순간 중복해서 메모리에 올리는게 아니라 이미 올라간 쉐어드 라이브러리를 공유해서 쓴다

물리적 메모리 관리 기법

오른쪽 그림이 물리적 메모리
낮은 주소영역에는 운영체제 커널이 상주
나머지 영역에는 사용자 프로그램이 올라간다
사용자 프로그램이 올라간 주소 영역 어떻게 관리할까?

  • 연속할당

    • 프로그램이 쪼개지지 않고 통째로 올라가는 것
    • 주소변환이 간단하다
      시작위치만 알면 얼만큼 떨어져있는지만 더해준다
  • 불연속할당

    • 프로세스 주소공간이 잘려서 산발적으로 올라가거나 쫓겨날 수 있음

연속 할당


  • 고정분할
    • 물리적 메모리를 4개의 파티션으로 미리 나눔
      각각 파티션에는 프로그램 하나씩 들어감
      프로그램 A가 분할1에 들어갈 크기 > 들어가서 실행
      프로그램 B는 분할 2에 작아서 못들어가고 3에 들어감
    • 분할3에서 남는 공간 생김 > 내부 조각
      낭비되는 조각이 생겨서 비효율적
    • 분할 2도 크기가 안맞아서 활용이 안됨 > 외부 조각
  • 가변분할
    • 미리 나누지 않고 차례로 실행되면 낭비되는 공간 없이 쓸 수 있다
    • B가 종료되면 비어서 다른 프로그램이 올라갈 수 있다
    • D 크기가 외부조각보다 더 크면 뒤에다 넣음 (크기가 안맞음) > 외부조각
    • 내부조각이 생기지는 않는다
      개념적으로 못들어가는거지 나중에 맞는 프로그램이 들어가면 낭비 공간은 아니기 때문에 개념적으로만 보기

  • 홀 조각들은 다 가용메모리 공간
    프로그램 실행되고 종료되고 그러다 보면 홀이 여러군데 작게 생길 수 있다
  • 운영체제는 사용중 공간과 가용공간을 유지해야 한다

어느 홀에 올릴 것인가?

1. 퍼스트핏
빈 공간 중 발견되는 제일 첫번째 공간에 올리는 것

  1. 베스트 핏
    여러 홀 중 가장 적합한 곳
    장점은 큰 공간은 유지하고 맞춤형 할당
    단점은 탐색

  2. 워스트 핏
    제일 큰 홀에 집어넣는 것
    큰 홀은 더 큰 프로그램을 위해 쓸 수도 있기 때문에 부적절한 측면이 있다

퍼스트와 베스트가 워스트보다 더 효율적

  • 컴팩션
    • 홀을 모아서 쓰는 방법
    • 고비용
    • 메모리를 이동시키기 때문에 비효율적
    • 이론적으로 복잡하다
    • 실행중 프로그램 물리적 주소가 동적으로 바뀌므로 바인딩 중에서 런타임 바인딩에서만 컴팩션이 가능

0개의 댓글