[운영체제] 3. 메모리 관리(5/5)

3.5 페이징 시스템의 설계 이슈

 

페이징 시스템의 디자인 이슈 : 페이지 크기, 부하처리, 메모리를 굉장히 많이 쓰는 경우 처리 등

가상 메모리 시스템에서는 현재 사용하는, 참조되는 페이지 프레임만 교체할건데 어디서 교체하느냐?

 

3.5.1 로컬/전역 할당 정책

local은 프로세스가 만들어질 때 몇 개의 테이블을 사용해야 하는가를 알아야 함.

 

모름 -> 상수로 정함 -> 동작하면서 페이지 폴트 -> 폴트 횟수를 사렾보며 필요한 프레임의 개수 정해주기 -> 워킹셋의 크기

-> 잘 정해지면 잘 동작. 충분히 큰 페이지 프레임을 할당할 수 있음

but 충분히 확보 못하면 메모리에 로드 못하고 실행못하게 됨. 또 특정 프로세스에 몰아주면 그 프로세스가 안쓰는데도 다른프로세스도 못쓰는. 낭비되는 프레임이 생길 수 있음.

 

global은 모든 프로세스의 전체 페이지 프레임을 교체 대상으로 삼음 -> 전체 워킹셋 변화에 잘 적응하지만, 프로세스가 많아지면 폴트 많아지고 실제 프로세스 진행은 불가능해짐.

 

에이지가 클수록 최신 페이지. b는 로컬이니까 a5번이 쫓겨나고 6번이 로드된 반면 c는 b3가 교체됨.

-> 이 둘을 적절히 세팅해야 합니다. 페이지 개수가 많아질수록 폴트가 줄어듦 : 페이지폴트가 많거나 적거나가 아닌 중간지점에 세팅되어야 함. : 시간이 지남에 따라 관찰 필요

요즘엔 글로벌 위주로 사용. 로컬이 구현된 운영체제에서는 어떤게 사용되는지 알기때문에 그 중 필요없는걸 교체하곤 함...어려움..

 

 

3.5.2 load control(부하 제어)

thrashing : 메모리가 부족하여 코드페이지 데이터 전부 물리 프레임에 올라오지 않아 페이지 폴트 반복

로드 컨트롤 : 프로세스 스케쥴링 중 심각한 상황이면 서스펜드 하는 중기 스케쥴링. -> 이를 sawpper가 몇 개 프로세스를 한 후 -> 이후 실행 재기

 

 

3.5.3 페이지 사이즈 : 시스템과 피지컬 메모리 사이즈가 증가 추세 : 페이지 사이즈가 1기가짜리도 있음, huge page

기본적으로는 4k : cpu디자이너가 결정

-> 내부 fregmantation을 고려해야 함 : 사용되지 않은 공간이 클수록 낭비.

페이지 테이블의 사이즈가 커지면 페이지 사이즈는 작아지고, 페이지 사이즈가 커지면 테이블 사이즈는 작아지지만 로드해야할 게 많아짐

 

수학식이 있는데, s/p : overhead. e(엔트리사이즈) : 2, 비용은 페이지테이블의 크기 + 페이지의 반이 낭비 -> -se/p^2 + 1/2(p는 페이지 크기)

 

이p를 증가시키면 u자 모양이 됨 -> 페이지 사이즈가 작으면 테이블 사이즈가 커져서 낭비, 페이지 사이즈가 크면 내부 프레그맨테이션 때문에 낭비. -> 최소값은 미분해야겠지? sqrt(2se)가 됨 : s는 메모리 크기 1mb, 해시테이블 엔트리 : 8bit -> 4KB.

 

3.5.4 명령어와 데이터 공간 분리

32bit cpu의 경우 메모리를 많이 사용하는 프로세스 존재 -> 가상 메모리 공간을 2개로 나눔

Instruction space와 data space 로 나눔.

cpu가 이를 구분하려면 1bit가 필요한데, 그럼 주소 공간이 줄게되는데, 다행히도 cpu는 암묵적으로 코드와 데이터를 구분 가능.

 

 

3.5.5 공유 페이지 : 여러 사용자들이 같은 프로그램을 실행 -> 페이지 공유가 효율적

각 페이지 테이블의 동일한 페이지 프레임을 가리키도록 해서 공유.

copy on write : 유닉스에서 자식 프로세스를 만들 때 fork 시스템을 호출하는데, 자기 자신을 그대로 복제 -> 자기의 어드레스 스페이스 자체를 똑같이 복사.

모든 데이터 페이지는  read속성으로 맵핑. 원본을 한 프로세스가 수정시도시 속성 위반으로 운영체제에 트랩이 걸림 -> 쓰려는 데이터가 저장된 페이지에 대한 복사본을 만들고, 변경된 데이터를 저장. 각 프로세스는 자신의 페이지를 가리키게 됨 -> 이 페이지의 속성은 read-write가 됨 -> 이제 쓰기가 가능해짐. 

 

파란 부분 전체를 할당하는 것이 아닌, 일부 페이지 테이블 엔트리를 할당해주고 그 곳에 카피 온 롸이트를 둠. 이렇게 페이지를 공유하면 자식프로세스 만들 때 포크의 오버헤드를 줄일 수 있음.

 

3.5.6 공유 라이브러리

 

-fPIC옵션 : offset 36K의 위치가 어떤 주소가 아닌 program counter이 됨 -> 이 주소의 오프셋으로 접근

-> 재배치의 성능저하가 일어나지 않음.

 

3.5.7 파일 매핑

파일을 메모리에 매핑하여 파일을 읽고 쓰는 것을 간단하게 해줌.

두 개의 프로세스가 공유한 파일을 매핑해서 데이토 공유도 쉽게 가능 : memory mapped file

 

3.5.8 cleaning policy

page fault시 쫓아내야하는 프레임이 더티 프레임이면 swap영역에 써야하고, 시간이 어마어마하게 걸림.

-> 여유 페이지 프레임을 확보하자. -> 줄어들면 프로세스의 기능을 멈추고 여유 페이지 확보하고 다시 프로세스 시작

 

핸드 2개를 사용하여, 먼저 레퍼런스 비트를 0으로 쭉 클리어를 하고 그 프론트 핸드를 백 핸드가 쫓으면서 0인 녀석들을 사냥!

 

3.5.9 가상 메모리 인터페이스

메시지 패싱 : 프로세스는 각자의 메모리 공간이 있기에 타 공간에 접근 불가 -> 메시지 패싱을 통해 데이터 전달 가능

-> 동일한 페이지를 매핑하여 전달하면 효과적이다.

하나의 프로세스가 머신 A에서 원격지 메모리에 있는걸 확인하고 그걸 로컬로 복사 -> 페이지 테이블 엔트리를 업데이트

요즘엔 idma라는 기술 사용. 리모트 다이렉트 메모리 엑세스.

 

3.6.2 페이지 폴트 핸들링

씨피유가 페이지 가상 주소를 물리주소로 변경하려다 실패하면 -> 페이지폴트 발생 -> 씨피유는 현재 program counter를 씨피유에 저장하고 핸들러를 실행 -> 핸들러는 어셈블리 코드가 존재페이지폴트를 발생시킨 프로세스의 문맥을 저장해야하는데 어셈블리 코드로  레지스터뿐만이아니라 스택에 있는 정보들 전부 다 백업 : 이게 핸들러의 진입부가 해주는 것.

-> 핸들러가 동작하여 어떤 페이지가 폴트인지 확인-> 그리고 그 페이지가 언제 들어올 수 있는지 확인 -> 페이지 폴트가 발생한 이유를 알아야 함. 좀 전에 얘기했지만 페이지 테이블 엔트리의 페이지 프레임 번호가 없을수도 있음

 

최초 폴트 -> 프로세스 테이블에서 이 어드레스가 밸리드한지 판단해야지 -> 밸리드하지 않으면 잘못돈 메모리 액세스니까 그 처리를 하면 되고 정당한 메모리 엑세스인데 폴트가 났으면 그거에 해당하는 페이지를 찾아야함 -> 페이지 프레임으로 올려야지 -> 그럼 이제 페이지 교체를 해야되는 것.(p260 참조)

 

만약 선택된 프레임이 더티라면 -> swap에 씀 -> 프로세스 중지 -> 그 사이 다른 프로세스가 실행 -> 쓰기 요청이 완료되면 디스크 인터럽트 핸들러에 다 완료되었다고 확인하고 -> 현재 수행중인 프로세스를 정지시키고 -> 페이지 폴트 핸들러로 돌아와서 깨어나 하던일을 재실행

 

인터럽트 발생시 현재 실행중인 instruction을 종료 후 핸들러로 점프

페이지 폴트 핸들러는 코드를 수행하려고 주소전환하다가 폴트 -> instruction을 실행시킬 수 없어 -> 실행중인 명령을 백업시켜놔야함

 

따라서 폴트난 인스트럽션을 끄집어오고, 레지스터 정보 세팅하고, 처리 후에 재기시켜주게 됨.

 

 

3.6.3 인스트럭션 백업

인스트럽션 수행할 때 페이지 폴트 최대 3번. move의 인스트럭션 가져올 때 맵핑이 되지 않아 폴트,

A1에서 폴트,A0에서 폴트.

또 각각 patch해올때, 그리고 move가 A1이 쪼개져 있으면 또 폴트. 2번.

세컨드 오퍼랜드도 쪼개질 수 있으니까 6번도 가능. -> 사실 이런 명령어들은 한 페이지에 들어오게끔 함. 많이 나도 3번.

왜? 명령어 반입할 때 1번, 2개의 오퍼랜드 참조하기위해 각각 한번씩 총 3번 가능.

ex) 프로그램 카운터가 1002일 때 폴트가 발생했다면, 명령어의 연산부호인지 1000번지에서 시작한 명령어의 오퍼랜드인지 알 수 없음.

 

3.6.4 page lock : 락 비트는 운영체제에서 사용. I/O장치가 DMA를 이용해 데이터를 전달하고 있엇다면, 일부의 내용은 I/O의 내용이 되고 일부는 페이지 폴트에 의해 적재된 내용이 될 수 있음. -> 락을 설정하여 교체되지 않도록 함.

 

3.6.5 백킹 스토어

물리 페이지 프레임을 각 프로세스가 공유하는데, 코드 부분을 공유하면 스왑 영역의 특정 위치에 적혀있는 이미지의 부분. 이 부분이 바뀌면 페이지 테이블을 찾아서 다른 프로세스의 페이지 테이블도 바꿔줘야 함. -> 복잡

-> 스왑 영역에 적혀있는 정보를 유지한 채로 디스크맵을 가지고 있고, 페이지 테이블 엔트리는 그 디스크맵을 가리키는 형태로 함(b)

 

 

3.6.6 정책과 메커니즘의 분리 : 유연성과 확장성에 도움

Mach 운영체제에서는 메모리 매니지먼트를 3 부분으로 나눔

메커니즘 : 실제 교체되는 방법. 페이지 테이블, 스왑 영역, 가상메모리 등 사용하여 실제 페이지 교체가 이루어지도록 함.

1. low level MMU handler

2. page fault handler

폴리시 : 어떤 페이지를 교체할 것인지 결정하는 방법 ex) LRU와 같은 알고리즘

3. 외부 익스터널 페이지가 사용자 수준에서 동작하도록 바꿈

페이지폴트 -> 핸들로 동작 -> 익스터널 페이저가 동작해서 읽어다가 자신의 주소공간에 복사 -> 페이지가 어디에 존재하는지 페이지 폴트 핸들러에게 알림 -> 페이지 폴트 핸들러는 외부 페이저의 주소 공간에서 unmap하고, 적절한 위치에 매핑해달라고 MMU handler에게 요청 -> 프로세스 재실행 

 

MMU와 페이지 폴트는 커널 내에서 동작. 이렇게 정책과 메커니즘을 구분하여 구현하면 -> 정책 때문에 커널을 수정하는 일이 줄어듦