열렬히.뛰기

9. 기타 고려 사항

운영체제 > part 4 : 메모리 관리 > 공룡책 10장 : 가상 메모리 > 9. 기타 고려 사항

페이징 시스템의 효과적인 실행을 위한 각종 고려사항.

프리페이징

💡 프로세스의 코드와 데이터를 필요한 시점에 미리 가져와 물리적 메모리에 적재하는 것

  • 순수 요구 페이징이 가진 특성; 프로세스가 시작될 때 많은 수의 페이지 폴트가 발생하는 것을 방지하려는 시도
  • 프리페이징을 사용하는 비용이 페이지 폴트를 처리하는 비용보다 적은지 따져봐야 함.
  • 어떤 페이지를 쓸지도 명확하지 않다면, 프리페이징이 쉽지 않을 수 있음.

페이지 크기

페이지 크기를 결정하는데 참고할 사항

  1. 페이지 테이블의 크기

    페이지 크기가 감소할수록, 페이지 테이블의 크기가 커진다.

    모든 활성 프로세스는 자기만의 페이지 테이블이 필요.

    이 관점에선 페이지가 클 수록 좋다.

  2. 할당해준 페이지 사용 효율

    이 관점에서는 작은 페이지가 좋다.

    할당한 메모리를 모두 사용한다는 보장이 없기 때문. (= 내부 단편화)

  3. 페이지의 읽고 쓰는 시간

    페이지가 늘어날 수록, 읽고 쓰는 시간이 더 늘어난다.

    페이지를 전송하는데 드는 시간은 페이지의 크기와 별 상관이 없다.

    그러나, 작은 페이지에서는 지역성이 향상되어 전체 I/O는 더 줄어들 것이기 때문에 메모리 총량도 덜 쓴다는 이점이 있다.

    그래서 이 관점에서는 작은 페이지가 더 낫다.

  4. 페이지 폴트 횟수

    페이지 폴트를 줄이려면 큰 페이지가 좋다.

다만 시대적으로는 페이지 크기가 커지는 추세.

TLB Reach

💡 TLB로부터 액세스할 수 있는 메모리 공간의 크기

TLB의 크기를 결정하는 것 또한 필요하다.

  • TLB에 사용되는 연관 메모리가 비싸고 전력을 많이 소모하기 때문.

이를 위해 TLB Reach를 쓰는데, 이는 TLB 속 항목 수에 페이지 크기를 곱한 것.

TLB Reach 늘리기

  • TLB 크기 늘리기 → 아무리 늘려도 TLB에 다 안 들어가는 프로세스가 있다.
  • 페이지 크기 늘리기 or 여러 페이지 크기를 제공
    • 페이지 크기 늘리기 : 단편화가 증가할 수 있음.
    • 그래서 여러 페이지 크기를 제공한다.

역 페이지 테이블

역 페이지 테이블이 전체 가상 주소 공간에 대한 정보를 유지하지는 않음.

  • 참조된 페이지가 현재 메모리에 없을 때 문제가 됨
  • 이 정보를 공급하기 위해서는 프로세스 당 하나씩 확장된 페이지 테이블을 유지해야 함.

확장된 페이지 테이블 = 원래 페이지 테이블과 같음.

  • 그러나 이는 페이지 폴트 시에만 참조. 빨리 읽을 필요가 없다.
  • 그러므로 그 자체가 페이징될 수도 있다.
  • 읽어들일 때 또 다른 페이지 폴트를 부를 수 있으므로 커널에서 조심스럽게 처리해야 함.

프로그램 구조

사용자가 요구 페이징을 직접 다루는 방식을 생각해보자.

배열이 행 중심으로 저장되었다고 가정해보자.

python
for j in range(128):
	for i in range(128):
		arr[i][j] = 0; 

이 경우 각 행이 한 페이지를 점유하게 됨.

따라서 페이지 폴트가 128^2번 나게 됨.

python
for i in range(128):
	for j in range(128):
		arr[i][j] = 0;

이 경우에는 페이지 폴트가 128번만 나게 됨.

즉, 자료구조와 코드의 구조를 잘 맞추면 지역성을 향상시킬 수 있음.

→ 페이지 폴트율과 작업 집합의 페이지 수를 줄일 수 있다는 이야기

컴파일러와 로더도 페이징에 큰 영향을 미칠 수 있음.

<컴파일러>

  • 코드와 데이터를 분리하는 것, 재진입 코드를 생성하는 것을 코드 페이지를 읽기 전용으로 만들어 코드 페이지를 변경하지 않게 한다.
  • 변경되지 않은 페이지는 교체 시 페이지 아웃 하지 않아도 된다.

<로더>

  • 하나의 루틴을 페이지 경계에 걸치지 않게 하여 각 루틴이 한 페이지 안에 완전히 들어갈 수 있게 할 수 있음.
  • 서로 호출하는 빈도가 잦은 루틴끼리는 서로 같은 페이지에 위치시키기

I/O 상호 잠금

요구 페이징을 사용할 때, 그 페이지의 일부를 메모리에 고정하는 것이 필요.

이 상황은 I/O가 사용자 공간에서 이뤄질 때 발생.

  • I/O는 별도의 I/O 처리기에서 실행

그러나 다음과 같은 이벤트가 일어나면 안됨.

  • 어떠한 프로세스가 I/O를 요구
  • CPU는 다른 프로세스에 할당
  • 갑자기 이 프로세스가 페이지 폴트를 일으키고, 대기 중인 프로세서의 버퍼 메모리를 포함한 페이지를 교체
    • 그 페이지는 페이지 아웃
  • 시간이 흐르고, I/O 작업 처리.
  • 그치만 원래 버퍼가 있는 프레임은 이미 타 프로세스가 사용

이를 막기 위해 크게 2가지 방법이 있음.

  1. 사용자 공간에서는 I/O를 하지 않음.
    • 실제 I/O는 시스템 공간과 장치 사이에서만 함
    • 데이터 : I/O → 시스템 공간 → 사용자 공간
    • 오버헤드 발생 가능성이 높아짐.
  2. 페이지를 메모리에서 잠금하는 것.
    • 잠금 비트를 프레임마다 두고, 만약 프레임이 잠기면 교체 대상에서 제외하는 방식
    • 디스크에 블록을 쓰기 위해서는 해당 블록을 담고 있는 페이지를 일단 잠그고, I/O가 끝나면 풀어줌.

잠금 비트를 사용하는 사례

  1. 운영체제 커널의 일부나 전체를 메모리에 잠근다.
  2. 사용자 프로세스를 잠근다. (ex. 데이터베이스 프로세스)

이러한 페이지 고정을 위한 시스템 콜이 운영체제마다 존재.

한편, 페이지 고정은 악용될 수 있으며 메모리 관리 알고리즘에 부담을 줌.

메모리 고정 요청은 앱이 직접 특권을 가져야 함.

잠금 비트 사용이 위험한 경우

  • 잠금 비트가 해제되지 않는 경우 : 이 경우 잠긴 프레임을 사용할 수 없다.