각 프로세스마다 0번지 부터 시작하는 논리주소 공간을 가짐(Virtual Memory)
CPU가 보는 주소
주소변환 과정에 OS는 참여하지 않는다. 오직 하드웨어가 관여한다.
즉 여기에서 OS의 역할은 없다.
메모리에 실제 올라가는 위치
주소를 결정하는 것이다.
Symbolic주소 -> Logical 주소 는 컴파일에서 이루어 진다.
그 후 Logical주소에서 Physical주소로 바뀌는 것이 바로 주소바인딩이다.
논리주소 그대로
비어있는 곳 찾아서 할당
Load time binding처럼 처음에는 비어있는 곳에 할당했다가 실행 도중 이동이 가능하다.
이동할때는 MMU가 변환한다.
물리적 메모리에 실행파일 코드 주소가 그대로 올라간다.(ex> Add 20, 30)
CPU가 그 위치의 해당 논리주소에만 접근하면 MMU가 이거를 바꿔서 접근하게 해준다.
그때그떄 루틴이 불려 질때마다 그 루틴을 메모리에 올림
생각보다 자주 사용되는 프로그램은 한정적임 (통째로 메모리에 올리면 비효율적임)
OS가 라이브러리로 프로그래머가 동적할당 할 수 있게 도와줌
메모리에 실제 필요한 부분만 올림
OS의 지원없이 프로그래머가 코딩을 통해 어디다 올릴지 짜야함
프로세스를 일시적으로 메모리에서 HDD(Backing Store: swap area)로 쫓아냄
메모리에 너무 많은 프로그램이 올라와 있으면 시스템이 비효율적이 됨
따라서 중기 스케줄러가 일부 프로그램을 골라서 통째로 메모리에서 디스크로 쫓아냄
즉 CPU 수행가능성이 낮은 프로그램들을 골라서 메모리에서 HDD로 스왑 아웃 시킴
Swap Out을 당해도 물리메모리에 다시 Swap In 될때 원래주소로 가기 보다는 다른위치로도 비어있다면 갈 수 있게 해주는 Runtime binding이 사용되면 좋다.
라이브러리가 프로그램의 실행파일코드에 포함됨
ex> printf 프로그래밍
내가 만든 프로그램에 이미 printf의 코드가 포함되어 있다.
즉 내 프로그램 주소 공간에서 실행됨
내 코드안에 라이브러리가 없지만 별도의 라이브러리 파일 위치를 찾을 수 있는 stub라는 작은 코드를 둠
-> 찾아서 필요하면 메모리에 올리고, 이미 올라와 있다면 그 주소로 가서 라이브러리를 실행함
가장 적절한 hole을 찾아서 할당하는 것이다.
Hole 중에서 제일 먼저 찾아진 hole에다가 할당한다.
Hole을 다 찾아본뒤 프로그램 크기와 가장 잘 맞는 hole에다가 프로그램을 올려놓는다.
가장큰 hole에 프로그램 할당 (어리석은 방법)
외부조각으로 생기는 hole들을 한군대로 몰아서 아주 큰 hole을 만들어서 hole의 크기가 작아서 사용이 안되는 문제를 해결할 수 있다.
고정분할과 가변분할이 있다.
프로그램이 메모리에 올라갈 때 통째로 메모리에 올라간다.
고정분할은 분할 4개를 미리 나누어 놓는다 즉 융통성이 없다.
즉 뭔지도 모르고 나눠 놓았기 때문에 외부조각도 나오고 내부조각도 나온다. (공간 여분)
가변분할은 차곡차곡 공간에 프로그램을 올려놓는다.
그런데 B가 끝나고 D가 실행이 되면 B공간은 너무 작기 때문에 밑으로 들어가고 외부조각이 발생한다. 내부조각이 발생하지는 않는다.
프로그램마다 별도의 pagetable이 존재해야한다.
프로그램을 구성하는 주소공간을 잘개 쪼개서 일부는 이쪽 일부는 다른쪽에 할당한다.(여기저기 흩어져 있다.)
1) 페이징, 2) 세그멘테이션, 3) Paged Segmentation
즉 2번의 메모리 접근이 필요해진다.
1) pagetable을 참조하여 주소변환(MMU가 함) 2) 변환된 주소에 접근
따라서 속도향상을 위해 별도의 하드웨어인 TLB를 사용한다.
페이지 테이블과 MMU의 관계
페이지 테이블은 메모리 관리에 필요한 주소 매핑 정보를 저장하는 데이터 구조이고, MMU는 이 페이지 테이블을 참조하여 실제 주소 변환 작업을 수행하는 하드웨어 장치이다.
즉, 페이지 테이블은 변환 정보를 제공하고, MMU는 그 정보를 사용하여 주소 변환을 실제로 수행한다.
사용되는 레지스터
1) page-table base register(PTBR): 메모리상에서 Pagetable이 어디에 있는지 그 시작위치
2) page-table length register(PTLR): 페이지 테이블의 길이
자주쓰는 주소를 pagenumber, framenumber를 매핑하여 캐시형태로 두고 있다.
p라는 페이지에 대한 주소 변환정보가 TLB에 있는지 확인하려면 전부 찾아봐야함! 만약 없으면 일반적인 방식으로 전환한다.
문맥교환시 비워진다. 프로세스마다 다른 TLB를 가진다.
페이지 테이블 접근해서 메인 메모리에서의 시작주소를 GET한다. (1번 접근)
페이지 테이블에서 얻은 주소로 물리메모리에 접근하여 데이터를 얻는다.(2번 접근)
결론 Page 테이블은 실제 RAM(물리적 메모리)에 있기 때문에 이거에 접근하는거보다 캐시를 두어서 캐시 장치(TLB)에 먼저 접근해서 속도를 높인다.
실제로 안쓰는 곳이 많음에도 페이지 테이블은 똑같이 만들어진다.
즉 공간 낭비가 심하다.
따라서 Outer테이블을 하나 더만들어서 거기서 실제로 쓰는 공간만 매핑(페이지 테이블)하겠다라는 것이다.
현재의 컴퓨터는 메모리 주소체계가 매우크다(64비트)
결론: 전체 주소공간 중 생당부분은 실제로 사용하지 않기에 바깥쪽 페이지 테이블에 NULL을 넣는다. 따라서 실제 값이 있는 부분만 안쪽 테이블이 만들어진다.
논리메모리 주소크기 = 바깥쪽 페이지 테이블 크기(그러나 NULL이 삽입)
실제로 Multilevel Paging and Performance 를 통해 outer 테이블을 여러개 만들 수 있지만 테이블을 거치는 시간때문에 성능에 문제가 발생한다.
프로그램이 0번, 7번 사용안하지만 페이지 테이블은 프로그램의 주소공간이 가질 수 있는 최대 사이즈 만큼 엔트리가 생긴다. 이를 i로 표기한다.
페이지 테이블 각 엔트리마다 아래의 bit를 둔다.
어떤 연산에 대한 접근 권한 (page에 대한 접근 권한: read/write/read-only)
valid: 해당 주소의 frame에 그 프로세스를 구성하는 유효한 내용이 있음(접근 허용)
invalid: 해당 주소의 frame에 유효한 내용이 없음을 뜻함(접근 불허)
-> 프로세스가 그 주소 부분을 사용하지 않음, 해당 페이지가 메모리에 올라와 있지 않고 SWAP AREA에 있는 경우
지금까지의 문제는 Pagae Table의 용량이다. Inverted Page 테이블은 엔트리가 물리적메모리의 페이지 프레임 개수만큼 존재한다.
이제 진짜로 올라와 있는거만 페이지 테이블에 존재한다.
1) 어떤 프로세스의 p인지 전수조사(pid를 도입)
2) 찾은 위치의 인덱스를 구한다.(f)
3) f랑 d로 실제 데이터 접근한다.
그러나 전수조사 덕에 시간적인 오버헤드가 존재한다.
아래한글을 3개의 프로그램으로 돌리고 있다.
프로그램의 코드 부분은 3개의 프로세스가 똑같이 쓰면 된다.
공유할 수 있는것은 같은 프레임에 Mapping 시킨다(Shared Code)
의미 단위로 쪼갠다
Code, Data, Stack 부분이 하나씩의 세그먼트로 형성된다.
의미 단위로 일할 경우 세그멘테이션이 효과적임, sharing에 효과적, 보안에 효과적
그러나 Segment의 길이가 각각 다르므로 allocation 문제가 발생
first fit / best fit 등의 기법을 써야한다.
물리적 메모리에서의 segment table의 위치
프로그램이 사용하는 Segment의 수
세그먼트 하나가 여러개의 페이지로 구성(크기가 달라져서 생기는 allocation 문제 해결)
즉 세그먼트 당 페이지 테이블이 존재한다.
결론: 세그먼트 테이블 해당하는 세그먼트 마다 표시함(의미단위)
물리적 메모리에 올라갈 떄는 페이지 단위(allocation 문제가 발생하지 않는다)
2가지 장점을 취한다.