computer science

[OS] 운영체제 Memory management

yjs3819 2021. 8. 29. 17:59
728x90

운영체제가 어떻게 메모리를 관리하는지 알아보자.

그전에 먼저 메모리에 대한 용어들 부터 알고 가자

메모리(기억장치)의 종류

레지스터는 cpu core내부에 존재하고, 캐시는 cpu내에 존재하는걸 확인할수있다.(그림에서)
메인메모리와 보조기억장치는 cpu내부에 없고 외부에 존재한다.
즉,

  • 레지스터, 캐시는 HW(cpu)가 관리하고
  • 메인메모리, 보조기억장치는 SW가 관리한다.

메모리(기억장치)의 계층구조

메모리는 보조기억장치 -> 메인 메모리 -> 캐시 -> 레지스터로 데이터를 전송하는 계층구조로 존재한다.

알아야할 두가지 용어

  • block : 보조기억장치가 주기억장치(메인메모리)로 데이터를 전송하는 단위(1 ~ 4KB)
  • word : 주기억장치(메인메모리)가 레지스터로 데이터를 전송하는 단위(16 ~ 64bit)

window 64bit 컴퓨터란 word가 64bit로 메인메모리에서 레지스토로 한번에 전송할수 있는 데이터 단위가 64bit라는 뜻이다. 높으면 그만큼 cpu연산 속도가 높겠다. 과거에는 wordr가 8bit 였던 적도 있다고한다..

Address Binding

프로그램의 논리주소를 실제 메모리의 물리 주소로 매핑하는 작업을 의미한다.

int a;라는 변수이름 a는 논리주소이고 실제로 소스코드가 실행되면 실제 메모리에 올라가야하는데, 올라갈 메모리의 실제 주소가 100이라면 물리주소는 100인것이다.
이 a -> 100으로 매핑하는 작업을 Address Binding이라고 한다.

언제 Address Binding이 일어나냐에 따라 구분할수 있다.
그전에 우리가 만든 소스코드가 실제 메모리에 올라가서 실행되기까지의 그림을 확인해보자.

Compile time binding

소스코드가 컴파일러에의해 Object module이 될때 즉, 컴파일 될 때 논리주소를 물리주소로 매핑하는 Address Binding이다.

  • 컴파일러가 address binding을 한다.
  • 컴파일러가 메모리를 모두 알고있어서 어느 부분의 메모리가 비었는지를 알아 해당 위치를 사용하여 물리주소로 변환한다.
  • 프로그램 전체가 메모리에 올라가야한다. 이미 논리주소와 mapping된 실제 주소의 메모리에 올릴 것을 염두하고 컴파일하기에.

Load time binding

Linker로 오브젝트 모듈들을 Load 모듈(.exe - 실행파일)로 만들고, Load 모듈들을 메모리에 적재할 때 논리주소를 물리주소로 매핑한다.

  • 컴파일 시점에는 메모리에 적재할 위치를 모르기에 상대주소를 이용한다. (메모리에 적재될 시작 주소를 가정한다.)
  • 실제 메모리에 적재될 때 가정한 상대주소에 실제 메모리에 적재되는 시작 주소를 더해서 실제 주소로 매핑한다.
  • compile time binding과 같이 프로그램 전체가 메모리에 올라가야한다.

Run time binding

메모리에 프로그램을 올릴 때 까지도 address binding을 하지 않다가, ready상태의 프로세스가 running상태로 돌입될 때, 즉 프로세서가 프로세스를 할당하여 프로세스가 수행될 때 Address Binding을 한다. 프로세스가 프로세서(cpu)를 할당받아 작업을 수행할 때마다 address binding을 하기에, 프로세스가 적재될 메모리의 위치는 계속 바뀔수 있다.(프로세스는 프로세서를 할당받으면 계속 끝까지 할당받는게 아닌, block상태로 갔다가, ready상태로 갔다가, running상태로도 갈수 있으므로 ready -> running으로 갈때마다 실제 프로세스가 적재될 메모리의 위치가 변경된다는 의미이다.!!!!!@!@!@!@!@)

  • MMU(Memory management Unit)이라는 HW도움이 필요하다.
  • 대부분의 OS가 사용하는 Address Binding이다.

Dynamic Loading

모든 루틴을 교체 가능한 형태로 디스크에 저장해 놨다가 실제로 해당 루틴을 프로세스가 호출하면 그때서야 메모리에 적재된다.

이는 다른 Address Binding처럼 프로그램 전체가 메모리에 올라가는게 아닌 호출될 때만 메모리에 적재되므로 메모리 공간을 효율적으로 사용할수 있다는 장점을 가지고있다. - 몬가 뒤에서 배울 가상메모리(non-continuous memory allocation)과 유사하군!

Swapping

프로세스 상태전이도에서 block <-> suspended block 을 swap이라했는데 그 swapping을 의미한다.
프로세스가 수행을 끝난 프로세스는 swap device로 보내지고(swap-out)
새롭게 시작하는 프로세스는 swap device에서 메모리에 적재된다.(swap-in)

vim으로 작업중 ctrl c나 바로 터미널을 꺼버리면 .swp파일이 생기는걸 경험해본적이 있다. 그때 수행중이던 프로세스가 메모리를 갑자기 뺏겨 swap device에 스냅샷을 저장하고 swap-out되는 것이였던 것이였던 것이였다..

Memory Allocation(메모리 할당)

메모리에 대한 기본지식을 쌓았으니 이제 우리가 만든 프로그램이 어떻게 메모리에 할당되는지 알아보자.

프로그램(프로세스)이 메모리에 할당되는 방법은 크게 두가지로

  1. Continuous Memory Allocation(연속할당)
  2. Non-Continuous Memory Allocation(비연속 할당)

로 나눌수 있다.

Continuous Memory Allocation(연속할당)

프로세스를 메모리에 연속해서 한번에 할당하는 방법을 의미한다.
프로세스 그 자체가 잘게 분리되지않고 메모리에 바로 연속적으로 할당된다.

메모리에 할당할 프로세스의 수에따라

  1. Uni-Programming : 프로세스 한개
  2. Multi-Programming : 프로세스 여러개

로 나눌수있다.

Uni Programming

하나의 프로세스만 메모리에 할당되는 것을 의미한다.
즉, 매우 간단한 메모리 할당 방법이다.

  • 문제점1
    그러나 프로그램의 크기 > 메모리의 크기 이면 어떻게할까? 뭔가 분할해야할거같다..

---> Overlay structure 해결법을 통해 공통 영역의 프로그램만 메모리에 올리고, 필요한 부분을 메모리에 올리고 다시 내리고 그다음 필요한 부분을 메모리에 올리는 형태로 메모리를 할당해야한다.
그러나 이런 해결을 위해선 사용자가 분할해야 하므로, 사용자가 프로그램의 상황 및 자료구조를 모두 다 잘 알고 있어야 하는 단점이 있다.

  • 문제점2
    커널은 많은 자원을 관리하기에 함부로 메모리가 커널에 할당되면 안된다. 그렇기에 커널을 보호해야한다.
    하나의 프로그램이 메모리에 할당될때 커널에 할당될수도 있으므로,, 커널을 보호하는 과정이 필요하다.

---> 이는 boundary register(경계 레지스터)를 이용하여 커널에 메모리가 할당되지 못하도록 경계 주소값을 통해 커널에 메모리 할당을 막을수 있다.

  • 문제점3
    너무많은 메모리의 낭비가 있겠다. 100MB의 메모리가 단지 1MB인 프로그램 하나만을 위해서 사용되면 나머지 99MB는 낭비가 되는 문제가 존재한다. 이건 시스템자체의 performance를 낮춘다.

---> 단 하나의 프로세스만 메모리에 할당하지않고 여러 프로세스를 메모리에 할당할수 있게하면된다. 이는 바로 알아볼 Multi Programming이다.

Multi Programming

여러개의 프로세스를 메모리에 할당할수 있는 것을 의미한다.

이때 여러개의 프로세스가 할당될 메모리를 분할해야하는데, 고정된 크기로 메모리를 분할할지, 가변의 크기로 메모리를 분할할지에 따라 구분할수 있다.

  1. Fixed Partition(FPM)
  2. Variable Partition(VPM)

Fixed Partition(FPM)

여러개의 프로세스를 메모리에 할당하기 위해 메모리를 고정된 크기로 분할하는 방법을 의미한다.
미리 고정된 크기로 메모리가 분할이 되어있다.
하나의 프로세스는 하나의 partition에만 적재될수있다. (process : partition = 1 : 1)
메모리는 고정된 크기로 분할되어있고 분할된 각 partition에는 프로세스가 하나씩 들어갈수 있다.

위 그림은 Fixed Partition의 자료구조 예이다.

Fixed Partition은 고정된 메모리에 하나의 프로세스만 적재될수 있기에 커널 보호를 위해 사용한 boundary register를 분할된 크기만큼 사용해야한다.

Fixed Partition과 Fragmentation(단편화)

  1. 내부 단편화

    위 그림처럼 아래서 부터 10MB, 9MB, 5MB가 낭비가 되는걸 볼수있다.

partition의 크기 > 프로세스의 크기일경우 하나의 partition에는 하나의 프로세스밖에 적재가 되지 않기에 메모리가 낭비가된다. 이를 내부단편화라고 한다.

  1. 외부 단편화

    위 그림처럼 Process 4가 메모리에 적재되야하는데 적재될수 있는 partition이 없는걸 볼수 있다.

남은 메모리의 크기는 (10 + 10 + 24)44MB로 Process 4의 크기인 30MB보다 큰데, 메모리에 적재될수가 없는 상황이 발생했다.

즉, 남은 메모리의 크기 > 프로세스의 크기 이지만 메모리에 적재될수 없는 경우를 외부 단편화라고한다.

내부단편화, 외부단편화는 모두 Continuous Memory Allocation으로 프로세스가 연속적으로 메모리에 할당되야하기에 발생한다는 것을 잊지말자. 프로세스가 연속적으로 메모리에 할당될 필요가 없으면 단편화 발생하지 않겠다!!

Fixed Partition결론

  • 고정된 크기로 메모리를 분할
  • 프로세스 : 파티션 = 1 : 1로 적재됨
  • 고정된 크기의 파티션에 하나의 프로세스만 들어가면 되기에 메모리 관리가 간단함
  • 내부/외부 단편화로 메모리가 낭비가 됨

Variable partition(VPM)

Fixed Partition은 단편화문제때문에 많이 비효율적이라는것을 알아보았다. partition을 프로세스가 필요한 크기만큼 동적으로 할당하면 안될까? 그러면 내부단편화 문제가 해결될 것이다. 프로세스가 필요로하는 메모리의 크기를 동적으로 할당한 partition을 생성하는 것이 Variable Partition(VPM)이라 한다.

  • 프로세스가 필요로하는 메모리의 크기만큼의 partition을 내어주기 때문에 내부단편화는 일어나지 않기에 메로리 낭비가 적다.

    이런식으로 프로세스가 메모리를 필요로할때마다 동적으로 그 크기만큼의 partition을 할당한다.

만약 메모리를 할당받은 프로세스의 작업이 끝나면?


프로세스 B가 메모리를 release한 상태이다.


만약 이상황에서 5MB를 필요로하는 프로세스 P가 메모리를 할당받으려고 온다면 어떤 partition에 프로세스 p를 적재할까?

Placement Strategy(배치 전략)

프로세스를 어떤 메모리에 배치해야할지에 대한 전략이다.

  1. First-fit(최초 적합)
    시작 주소로부터 메모리를 확인하며 프로세스가 필요로하는 메모리만큼 사용할수있는 주소를 찾으면 해당 주소의 메모리에 프로세스를 적재하는 전략이다. 즉 가장 최초로 찾은 메모리 주소에 프로세스를 적재하는 전략이다.
  • 간단한 장점이있음
  • 공간활용도가 낮을수 있다.
  1. Best-fit(최적 적합)
    프로세스가 들어갈수있는 partition중 가장 작은 partition에 배치하는 전략
  • 모든 파티션을 확인해봐야하니 그만큼 overhead가 존재한다.
  • 크기가 큰 partition을 유지할수 있는 장점이있다.
  • 작은 크기의 partition이 많이 발생하므로 작은 크기의 메모리가 필요한 프로세스들에겐 할당하지 못하는 단점이있다.
  1. Worst-fit(최악-적합)
    프로세스가 들어갈수 있는 partition중 가장 큰 partition에 배치하는 전략
  • best-fit과같이 모든 파티션을 확인해봐야하니 그만큼 overhead가 생겨 탐색시간이 길다.
  • 작은 크기의 partition발생을 줄이기에 작은 크기의 메모리가 필요한 프로세스가 많은 시스템(알고리즘)에 적합하다.
  • 큰 크기의 partition확보가 어렵다.(단점)
  1. Next-fit(순차 최초 적합)
    first-fit은 가장 최초의 파티션만 자주 사용될수 있는 단점이 있으므로 돌아가면서 메모리의 파티션을 사용하기 위해 마지막으로 사용한 파티션 다음의 파티션이 프로세스의 크기보다 크다면 해당 파티션을 사용하는 전략이다.
  • 간단해 오버헤드가 적다.
  • 공간활용도가 낮을수 있다.

프로세스를 어떤 메모리의 파티션에 배치할지에 대한 배치전략을 살펴보았다. 전략은 당신이 사용하는 시스템, 알고리즘 특성상 어떤게 유리한지 선택해서 사용하면 된다. 어떤것이 무조건 더 좋다, 나쁘다는 없다. 모든 전략은 각각의 장단점이 존재한다.

VPM 외부단편화 해결책


VPM도 이렇게 외부단편화가 생길수 있다. 사용할수 있는 메모리의 크기는 60MB상태에서 50MB가 필요한 프로세스 P가 오는 경우 외부단편화가 발생된다.

  1. Coalescing holes(공간 통합)
    파티션에 적재된 프로세스가 작업이 끝나 메모리의 파티션이 release될 때, 파티션을 통합하여(Variable Partition이라 가능한것!) 외부단편화를 해결할수 있다.

    (예시)
  2. Storage Compaction(메모리 압축)
    프로세스가 작업이 끝나 파티션 release될 때까지 기다리지 못하는 긴급한 상황에는 메모리를 압축시켜 외부단편화를 해결할수 있다.

    (예시)

그러나 Storage Compaction은 파티션에 적재되어 실행중이던 프로세스의 메모리 적재위치를 모두 옮겨야하므로 메모리에 적재된 프로세스의 실행을 멈춰야한다. 즉, 엄청나게큰 오버헤드가 존재한다. 그렇기에 매우 긴급할때, 특정시간에만 사용해야지 항상 메모리압축을 통해 외부단편화를 해결하려하면 오버헤드가 너무커서 시스템 성능이 느려지게 된다.

Continuous Memory Allocation 결론

프로세스는 결국 레지스터에 올라가야 cpu(프로세서)가 연산을 수행할수있다. 그렇기 위해선 메모리에 프로세스가 적재되야하는데 어떻게 적재할지, 어떻게 할당할지에 대해 알아보았다. 프로세스를 그대로 연속적으로 메모리 올리는 방법을 이번에 살펴보았고, 하나의 프로세스만 올릴지, 여러프로세스를 메모리에 올리지에 따라 구분할수있는것도 알게되었다. 여러 프로세스를 메모리에 올릴때, Fixed Partition과, Variable Partition을 이용해서 올릴수있다는걸 알았고 FPM은 내부/외부 Fragmentation(단편화)가 발생하여 메모리 효율이 떨어진다는 것도 알게되었다. VPM으로 단편화를 해결할수 있다. 그때 프로세스를 적재할 메모리를 고르는 배치 전략도 알아보았고 배치전략은 어떤게 좋다 나쁘다는것은 없고 상황에 따라 선택하면 된다는 것도 알게 되었다. 그리고 VPM도 외부단편화가 발생할수 있는데 해결하는 두가지 방법도 알아보았다.

 

참고

https://www.youtube.com/watch?v=o1TB9NWvG9w&list=PLBrGAFAIyf5rby7QylRc6JxU5lzQ9c4tN&index=26

https://www.youtube.com/watch?v=te-GU7NKa5Y&list=PLBrGAFAIyf5rby7QylRc6JxU5lzQ9c4tN&index=25

https://www.youtube.com/watch?v=es3WGii_7mc&list=PLBrGAFAIyf5rby7QylRc6JxU5lzQ9c4tN&index=24

728x90