[OS] Paging

페이징

새로운 프로세스를 메모리의 비어있는 곳(holes)에 넣어야할 때, holes이 연속되어있으면 새로운 프로세스를 넣을 수 있는데 빈 곳이 따로따로 나누어져있어 프로세스를 넣지못할 때, 이를 단편화라고 한다.

이를 위한 해결책이 해당 프로세스를 쪼개서 메모리의 비어있는 곳에 나눠넣는 것을 페이징이라고 한다.

그러면 CPU가 메모리에 특정 프로세스를 실행시킬 때, MMU를 통해 논리주소를 보내면, MMU는 메모리의 해당 프로세스 물리주소를 가져와서 CPU가 해당 프로세스를 실행시킬 수 있도록 도와주는 것이다. 그래서 CPU는 해당 프로세스를 연속적으로 실행시키는 것으로 알고 있지만, 사실 메인메모리에서는 프로세스가 나뉘어져 흩어져있는 것이다.

주소 변환 (Address Translation)

페이지 크기, 페이지 테이블(MMU), 논리주소를 통해서 물리주소를 알 수 있다.

CPU에서 논리주소를 낼 때, 메인메모리에서 물리주소를 어떻게 알아낼 수 있는지??

우선 MMU는 page table이라고 불리기도 하는데, page table의 각 페이지들은 index를 가지고 있다. 그리고 프로세스 또한 frame 별로 나뉘어져있는데, CPU가 논리주소를 낼 때, 우선 그 주소를 이진법으로 만든다. 논리주소는 두 주소로 나뉘어진다. 나뉘어지는 기준은 페이지가 몇 개인지, 즉 페이지의 크기에 따라서 정해진다.(2의 몇 제곱인지에서 몇이 displacement 쪽으로 결정된다.) 첫 번째는 페이지 index가 된다. 여기서 페이지 테이블 내부에 들어있는 값은 프로세스의 frame의 index가 있다. 그래서 이를 통해 프로세스의 특정 frame 값을 찾아내서 연결할 수 있다. 두 번째는 displacement 부분이라고 하는데, 이부분은 페이지의 크기(bytes)에서 2의 몇 제곱이 페이지의 크기인지에서 제곱의 수가 두 번째 값이라고 한다.

그 값을 제외하고, 앞의 페이지 크기를 활용해서 MMU의 index 값을 구하고, 그 값으로 프로세스의 frame index 값을 정한다. 그렇게 앞의 값만 물리주소로 바꿔서 이진법으로 표현해낸다.

내부단편화

  • Internal Fragmentation

프로세스 크기가(프레임) 페이지 크기의 배수가 아니라면, 마지막 페이지는 결국 한 프레임을 다 채울 수가 없게 된다. 이것을 내부 단편화라고 한다.

하지만 내부 단편화로 인해서 소비되는 메모리는 거의 없다. 내부 단편화의 최대 메모리 사이즈는, 페이지 크기의 - 1 이다.

페이지 테이블

MMU를 CPU 안에 넣을 수 있는데, 이는 CPU 안의 기억장치 레지스터로서 활용할 수 있다. 아니면 반대로 프로세스 내부에도 넣을 수 있다.

첫 번째인 CPU 안에 MMU가 위치할 때, 주소변환 속도가 빠르다는 것이 장점일 수 있다. 반대로 CPU 내부에 있게되면 사이즈를 크게 만들 수 없다는 것이 단점이 될 수 있다.

반대로 MMU를 메모리에 넣는다면, 페이지 테이블의 크기를 크게 넣을 수 있다. 하지만, 주소변환 속도가 느려지는 것이 단점이다.

그래서 해결책이 캐시메모리를 만들어서 속도가 느린점을 해결한다. 이는 CPU에 MMU를 붙여놓은 정도보다는 속도가 느리지만, 메모리에 붙여놓은 것보다는 빠를 것이다.

보호와 공유

  • 보호

모든 주소는 페이지 테이블을 경유한다. 그래서 페이지 테이블 엔트리마다 r, w, x를 비트를 둔다. 그렇게 해당 페이지에 대한 접근제어를 가능하도록 한다.

  • 공유

같은 프로그램을 쓰는 복수 개의 프로세스가 존재하면, 한 프로세스는 코드, 데이터, 스택이 구성되어야하는데, 이 부분에서 코드 같은 경우엔 같은 프로그램이기 때문에 공유가 가능하다. 단, 코드가 실행되면서 스스로 코드를 변경하는 경우가 없도록 해야한다. 이를 pure code(non-self-modifying code)라고 한다.

이를 통해 메모리 낭비를 방지하도록 한다. 공유가 가능하도록 하는 것은, 프로세스의 페이지 테이블 코드 영역이 같은 곳을 가리키게끔 한다.(페이지 테이블에 써있는 물리주소가 메모리의 코드 영역이 같은 곳을 가리키게 하면 됨)