[OS] Lec 8. Memory Management - Backgrounds (1/3)

ChoiYongHyeun·2024년 3월 19일
0

운영체제

목록 보기
11/16
post-thumbnail

오랜만에 다시 공부하는 운영체제 ..

요 며칠간 프로그래밍 언어만 보니까 조금 지쳐서 운영체제 공부를 해봤다. :)

원래 반효경 교수님의 강의로 공부하다가 유튜브에서 김덕수 교수님의 강의를 보았는데 너무 좋아서 넘어가도록 했다.


메모리의 종류

메모리는 레지스터 , 캐시 , 메인 메모리 , 보조 기억 장치로 나뉜다.

이런 메모리 구조의 계층적 구조는 다음과 같은 특성을 갖는다.

  • 레지스터 , 캐시는 CPU 내부에 존재하며 하드웨어인 CPU 가 관리한다.
  • 메인 메모리 , 보조 기억 장치는 CPU 외부에 존재하며 소프트웨어인 OS 가 관리한다.
  • 보조 기억장치부터 레지스터로 갈 수록 가격이 높아지며 속도가 빨라진다.

메모리 계층 구조

메모리는 계층 구조를 가지며 데이터들은

보조 기억 장치 -> 메인 메모리 -> 캐시 메모리 -> 레지스터 순으로 전달된다.

이 때 보조 기억 장치에서 메인 메모리로 전달되는 데이터 최소 전송 단위는 Block 으로1 ~ 4 KB 에 해당하며

메인 메모리 ~ 레지스터 사이의 데이터 전송 단위는 Word16 ~ 64 bit 에 해당한다.


논리적 주소와 물리적 주소

어떤 프로세스가 CPU 에 할당되어 실행되기 위해서는 프로세스가 메인 메모리 상에 할당 되어야 한다.

물리적 주소 (Physical address) 는 실제 메모리의 주소를 의미한다. 이런 물리적 메모리 주소는 실제 컴퓨터에서 해당 주소를 통해 메모리에 저장된 변수에 접근하는 등의 행위가 가능하며

프로세스를 시행하기 위해서는 물리적 주소에 접근해야 한다.

논리적 주소 (Logical address) 는 가상 메모리 주소 (Virtual Address) 라고 알려져있으며 논리적 주소는 물리적 주소를 추상화 시켜놓은 개념이며 , 실제 메모리 주소를 의미하지 않는다.

프로그램 생성 혹은 실행 중 생성된 주소로 프로세스가 실행 될 때 메모리에서 데이터를 보기 위해 보는 주소에 해당한다.

이런 논리적 주소는 어떤 방법을 통해 물리적 주소로 변경 되며 , 물리적 주소를 통해 프로세스는 메모리 데이터에 접근하거나 코드를 실행한다.


Addres Binding

각 프로세스가 실행되기 위해 메인 메모리에 담겨야 한다.

이 때 프로세스의 logical address 를 실제 physical address 로 맵핑하는 작업을

Address binding 이라고 하며 , 이는 Binding 시점에 따라 구분된다 .

프로세스가 메인 메모리에 담기는 과정에서 발생하는 3 가지 Binding 의 종류들이 존재한다.

과정을 순차적으로 살펴보자

프로세스가 메인 메모리에 담기는 과정과 Binding

우리가 만든 소스 코드가 실행되기 위해 메인 메모리에 담기는 과정은 다음과 같다.

인간이 이해 할 수 있는 소스코드는 Compiler 를 통해 기계가 이해할 수 있는 어셈블리어로 변경된다.

한 번 더 기계가 이해 할 수 있는 어셈블리어는 이진법으로 이뤄진 머신 코드로 변경된다.

이 단계에서 , 컴파일 단계에서 Binding 이 일어나는 경우를 Compile time binding 이라고 한다.


Compile time binding

컴파일 타임 바인딩은 프로세스에 존재하는 논리적 주소들이 (예를 들어 변수나 함수가 저장될 위치)

물리적 주소와 동일하게 맵핑시켜둔다.

그러니 컴파일 타임 바인딩은 논리적 주소를 물리적 주소로 변환 시킬 필요가 없다.

이렇게 고정된 논리적 주소를 이용하는 경우

사용자의 실제 물리적 주소와 프로세스의 논리적 주소가 맞지 않는 경우에는 오류가 발생한다.

예를 들어 프로세스가 사용하는 논리적 주소에 , 사용자의 다른 프로세스가 올라가있거나 다른 데이터가 들어가있다면 오류가 발생 할 것이다.

Compile time binding 은 아주 예전 ,메모리의 크기가 작고 한 메모리에 한 프로세스만 할당되던 예전에나 사용되던 바인딩이고

현재는 많이 사용되지 않는다.


컴파일 단계에서 바인딩이 일어나지 않았다고 가정하고 과정을 진행해보자

컴파일 단계를 통해 프로세스를 CPU 가 이해 할 수 있도록 변경시켜놨다고 하더라도

여전히 외부에서 불러와서 사용한 라이브러리 내에 존재하는 변수나 함수들의 조회는 불가능한 상태이다.

아직 외부 라이브러리에 대한 변환이 일어나지 않았기 때문이다.

Linker 는 외부 라이브러리의 변수나 함수 등을 찾고 우리의 변환된 소스코드와 합쳐

하나의 실행 파일 형태로 만들어준다.

이후 만들어진 실행 파일은 Loader 를 통해

만들어진 실행 파일을 컴퓨터의 메인 메모리에 복사한다.


Load time binding

이렇게 Linker ~ Loader 단계에 일어나는 binding 단계를 Load time binding 이라고 한다.

이 단계에서는 프로세스가 생성되는 당시 실제 물리적 주소를 알 수 없는 경우

논리적 주소를 통해 프로세스의 참조 값등의 주소를 구현해두고

실제 메모리에 실행 파일을 복사하는 과정에서

논리적 주소를 실제 물리적 주소와 맵핑 시킨다.

강의에서 제공하는 예시로 프로세스의 논리적 주소를 살펴보면 모든 메모리 주소가

0번 부터 시작하는 것으로 가정하고 코드를 구현해둔다.

그런데 만약 실제 메모리에 프로세스를 로딩하는 과정에서

논리적 주소인 0번부터가 아닌 400번부터 담기게 되었을 경우

논리적 주소로 맵핑된 참조값들의 주소를 물리적 주소에 맞게 변경해준다.

Compile time bindingLoad time binding 의 공통점

binding 기법은 몇 가지 공통점을 갖는데
우선 실행 되기 전에 논리적 주소와 물리적 주소가 맵핑된다는 점에서 공통점이 존재한다.

또 특징적인 공통점은 두 바인딩 방식 모두 사용하기 위해서는 프로세스의 코드 전부가 메모리에 올라가야 한단는 점이다.

이는 두 바인딩 방식 모두 fixed address 방식으로 실행 될 참조값들의 주소들이 실행 이전에 정해져있기 때문이다.

물론 Load time binding 방식은 논리적 주소들을 실제 메모리에 프로세스를 담는 loading 과정에서 프로세스가 담긴 메모리의 주소를 기준으로 하여 물리적 메모리 주소로 바인딩하지만

그럼에도 불구하고 각 참조값들의 주소는 실행 이전에 정해져있다는 사실은 같다.


Load time binding 이 발생하지 않았다고 가정해보고 진행해보자

Run-time binding

이 때 loader 를 통해 메모리에 프로세스들이 담긴 이후

실행 될 때 논리적 주소들을 실제 물리적 주소로 변경한다.

이는 하드웨어의 도움이 필요하며 MMU (Memory Management Unit) 이라 불리는 하드웨어를 이용한다.

대부분의 OS 는 런타임 바인딩을 사용한다.

런타임 바인딩은 메모리 주소를 실행 전 정적으로 바인딩 해두는 것이 아닌

실행 될 때 마다 동적으로 바인딩 시켜준다.

이러한 유연성은 실제로 필요한 메모리에만 참조값을 저장하고 해제하는 행위 등을 통해

모든 프로세스의 코드를 메모리에 올려둘 필요 없이 , 메모리를 더욱 효율적으로 관리 할 수 있게 만든다 .

다만 정적으로 주소를 바인딩 시켜두는 것에 비해

동적으로 메모리에 주소를 바인딩 시키는 것은 시스템 콜을 통해 일어나기 때문에 성능의 오버헤드가 많다.

이 부분은 가상 메모리를 공부 하고 , 따로 더 공부해봐야겠다.


다이나믹 로딩

로딩은 프로세스를 메모리에 옮기는 과정이였다.

이 때 프로세스를 메모리에 모두 올려두는 것이 아니라

프로세스 내의 코드 등을 모듈처럼 나눠 디스크에 저장해뒀다가

필요한 코드 영역이 호출 될 때 메모리에 해당 코드 영역을 메모리에 적재한다.

해당 코드 영역이 메모리에 적재 될 때 코드 영역 내 변수의 참조값 등도 동적으로 변경된다.


profile
빨리 가는 유일한 방법은 제대로 가는 것이다

0개의 댓글

관련 채용 정보