CPU에서 연산을 하기 위해서는 데이터를 가지고 해야 하는데, 이러한 데이터의 위치가 필요하다. 따라서 명령어는 피연산자 필드를 이용하여 데이터의 위치 정보를 제공한다. 주소 지정 방식은 피연산자 필드를 이용하여 데이터의 유효주소를 결정하는 방법이다.
절대 주소 지정 방식은 실제 메모리 주소, 즉 물리적 주소를 직접 사용하여 데이터를 참조하는 방식이다. 해당 데이터가 메모리 상에서 정확히 어디에 있어야 하는지 알 수 있어야 합니다. 주소 계산을 따로 하지 않기 때문에 접근 속도가 빠르고, 메모리 관리가 단순해질 순 있으나 프로그램이 고정된 메모리 주소에만 접근해야 하므로 재배치성이 떨어지고, 매모리 출동 가능성이 높아지게 됩니다.
상대 주소 지정 방식
은 기준 주소를 기반으로 Offset 을 더하거나 빼서 메모리의 특정 위치를 참조하는 방식입니다. 이는 프로그램이 메모리의 어디에 위치하든, 코드 내 주소가 상대적이기 때문에 재배치성이 뛰어나다. 또한 메모리 보호와 효율적인 사용이 가능하고 다양한 프로세스가 실행되는 환경에서도 메모리 충돌을 방지할 수 있습니다. 단, 절대 주소 지정 방식에 비해 주소 계산이 추가로 필요하기 때문에 성능이 조금 떨어질 수 있습니다.
절대 주소 지정 방식
은 메모리의 주소를 직접적으로 가지고 있기 때문에 메모리 접근이 직관적이고, 디버깅이 쉽지만 메모리 주소가 고정되어 있기 때문에 프로그램의 위치가 변경되면 코드 수정이 필요할 수 있기에 유연성이 떨어진다. 하지만 상대 주소 지정 방식
은 명령어 내에 포함된 주소가 PC 값에 상대적으로 저장되기 때문에 명령어의 메모리 주소가 유동적으로 지정된다. 이는 프로그램의 위치가 변경되어도 주소가 자동으로 계산되기 때문에 코드의 유연성이 높아진다. 하지만 한번 더 메모리를 탐색하기 때문에 절대 주소 지정 방식에 비해 상대적으로 속도가 느립니다.
유효 주소 (Effective Address)
유효주소란 메모리 접근을 위해 사용하는 실제 메모리 주소입니다.
메모리 분할이란 운영체제가 메모리를 효율적으로 관리하고 여러 프로그램들이 동시에 실행될 수 있도록 메모리를 나누는 기법입니다. 주기억장치(RAM)를 여러 개의 구역으로 나누어 각 프로그램이나 프로세스가 자신만의 메모리 영역을 가지도록 하는 방법이다.
메모리 배치 기법은 운영체제가 메모리에 프로그램이나 프로세스가 사용할 메모리를 할당하는 방법이다. 이는 프로세스가 실행되기 위해 메모리에 올라갈 때, 운영체제는 적절한 메모리 공간을 찾는데, 이 때 메모리 배치 기법을 통해 메모리 공간을 선택합니다.
내부 단편화는 할당된 메모리 내에서 사용하지 않는 공간이 발생하는 문제다. 고정 크기의 메모리가 할당할 때, 프로그램의 크기가 할당된 메모리 블록보다 작을 경우에 발생한다. 할당된 블록의 남은 공간은 다른 프로세스에서 사용할 수 없기 때문에 메모리가 비효율적으로 사용되는 문제이다.
외부 단편화는 메모라 공간이 여러 개의 작은 빈 공간으로 나뉘어져 있어, 충분한 전체 빈 공간이 있음에도 불구하고 새로운 프로세스를 적재할 수 없는 문제이다. 메모리 공간이 할당되고 해제되는 것을 반복하면서 작은 조각들로 나뉜 메모리 공간이 효율적으로 사용되지 않는 상태입니다.
Colaescing
기법은 메모리 관리에서 외부 단편화 문제를 해결하기 위해 사용되는 기법으로, 빈 공간의 메모리 공간들을 결합하여 하나의 큰 메모리 공간으로 만드는 기법입니다. 이 기법을 통해 메모리에 남아있는 조각난 작은 빈 공간들을 하나의 큰 공간으로 합칠 수 있어, 새로운 프로세스가 적재될 수 있는 충분한 메모리 공간을 제공한다.
Compaction
기법은 주로 동적 메모리 할당 시스템에서 메모리 단편화를 해결하기 위해서 사용하는 메모리 배치 기법입니다. 이는 메모라 블록들을 연속적으로 배치하여 메모리 단편화를 줄이고, 빈 공간을 확보하여 새로운 메모리 요청을 더 효율적으로 처리할 수 있도록 합니다.
메모리에서 사용 중인 블록들을 한쪽으로 이동시켜서 연속적인 메모리 공간들 만듭니다. 메모리의 빈 공간이 연속적으로 합쳐지게 되어, 큰 메모리 블록을 요구하는 프로그램이나 프로세스가 할당될 수 있습니다.
버디 시스템 (Buddy System)은 메모리 블록을 2의 제곱 단위로 관리하는 시스템을 의미한다. 만약 프로세스 메모리 적재에 대해 요청이 들어왔을 떄, 가장 큰 메모리 블록으로부터 시작해서 Binary로 절반씩 쪼개면서 요청된 프로세스의 매모리 크기 k 에 대해 2^(n-1) < k <= 2^n
를 만족시키는 n 을 찾고 2^n 만큼의 공간에 프로세스를 적재한다. 쉽게 이야기해서 1000 Kb 짜리 프로세스 메모리에 대해서 요청이 들어왔다면 512KB < 1000KB < 1024KB 이기 떄문에 1024KB 짜리 메모리 공간에 해당 프로세스를 적재하는 것이다.
이해가 잘 안된다면 그림으로 이해해보자.
1mb
-> 512kb
| 512kb
-> 256kb
| 256kb
| 512kb
-> 128kb
| 128kb
| 256kb
| 512kb
)페이징 (Paging)
은 메모리 관리 기법 중 하나로 물리적 메모리를 일정한 크기의 고정된 블록으로 나누고, 프로세스의 주소 공간도 동일한 크기의 고정된 블록으로 나누어 관리하는 방식이다. 각각의 페이지는 물리 메모리에 매핑이 되기 때문에 연속적으로 배치되지 않아 외부 단편화 문제가 발생하지 않는다.
Page Table
각각의 프로세스에서 사용하는 메모리 데이터들이 어느 프레임에 적재되어 있는지 CPU는 알기 어렵다. 이를 위해서 물리 주(프레임)에 불연속적으로 배치되더라도, CPU가 접근하는 논리 주소에 연속적으로 배치되도록 하기 위해 Page Table
을 이용한다.
PTBR (Page Table Base Register)
프로세스마다 Page Table이 존재하고 CPU 내의 Page Table Base Register 는 각 프로세스의 페이지 테이블이 적재된 주소를 가리키고 있다. 하지만 페이지 테이블이 메모리에 저장되어 있다면 메모리 접근 시간이 2배로 늘어나게 된다.
TLB (Translation Lookaside Buffer)
CPU 곁의 페이지 테이블 캐시 메모리이다. 페이지 테이블의 일부를 가져와 저장하는 캐쉬 메모리로서, 페이지 테이블의 접근 시간 2배 문제를 해결해준다.
TLB Hit
: CPU가 접근하려는 논리 주소가 TLB에 있는 경우
TLB Miss
: CPU가 접근하려는 논리 주소가 TLB에 없는 경우 )
세그멘테이션 (Segmentation)
은 프로세스를 논리적인 단위(Segment) 로 나누어 메모리에 할당하는 방식입니다. 페이징과 달리 세그멘테이션 방식은 메모리를 고정된 크기로 나누는 것이 아닌 프로그램의 논리적 구조에 따라 가변 크기 블록으로 나누어 집니다.
Segment
세그멘테이션에서 프로그램이 논리적으로 나누어 질 수 있는 독립적인 단위이다. 예를 들어 코드, 데이터, 스택 등은 각기 다른 목적을 가진 논리적인 정보이기 때문에 각각의 Segment로 나누어질 수 있습니다.
Segment Table
세그먼트 번호와 세그먼트의 기본 주소 (Base Address) 및 길이를 저장하는 데이터 구조입니다. 이 테이블은 가상 주소를 물리 주소로 변환하는데 사용됩니다.
프로세스는 여러 개의 세그먼트로 나뉘게 됩니다. 각 Segment는 고정 크기가 아닌, 프로그램의 요구에 따라 가변적인 크기를 가집니다.
각 프로세스는 Segment Table을 가지고 있고, 해당 테이블에는 Segment의 시작 주소와 세그먼트의 최대 크기가 기록됩니다. 가상 주소는 Segment Number와 Offset 으로 이루어져 있으며, Segment Number를 이용해서 Segment Table에서 해당 Segment의 기본 주소를 찾은 후, 거이에 Offset 을 더해 실제 물리 메모리 주소를 계산합니다.
Segment는 논리적 구조가 반영할 수 있고, 각 Segment는 독립적으로 관리되므로, 특정 Segment에 대해 R/W 권한을 따로 설정할 수 있습니다. ( 예를 들어 코드 영역은 Read만 하고 싶다 라고 할 때, Segmentation 기법은 코드 Segment만 권한 설정을 하면 되지만, Paging 기법의 경우, 그러한 데이터가 고정된 크기로 분할되었기 때문에 어디서 부터 어디까지가 Code 영역의 정보인지 알 수 없다. ) 또한 여러 프로세스가 같은 Segment를 공유할 수 있습니다. 또한 Segment의 크기가 가변적이기 때문에 필요한 만큼의 메모리를 할당할 수 있습니다. 이는 고정 크기의 페이지를 사용하는 Paging 기법보다 메모리를 보다 효율적으로 사용할 수 있습니다.
단, Segment의 크기가 가변적이기 때문에, 메모리 내에서 사용하지 않는 작은 조작들이 발생할 수 있다. 여러 번 메모리를 할당하고 해제하다 보면, 메모리 내에서 큰 연속된 빈 공간을 확보하기 어려워지는 외부 단편화
문제가 발생할 수 있다. 또한 페이징과 대비하여 Segmentation
기법은 테이블을 관리하는데 들어가는 비용이 더 들어가고, 주소 변환 과정이 더 복잡해지는 오버헤드가 발생할 수 있다.
지금은
Paging
vsSegmentation
기법 중 어떤 메모리 배치 기법이 많이 사용될까?
현대 시스템에서는 Paging 기법이 더 많이 쓰인다. Segmentation 기법은 외부 단편화 문제와 복잡한 관리 때문에 거의 사용되지 않는다고 한다. 페이징의 단순성, 외부 단편화 문제 해결, 가상 메모리의 지원 등의 장점이 현대 시스템서 더 적합하기 때문이다. 일부 시스템에서는 Paging-Segmentation 기법을 사용하기도 했으나, 현대의 시스템의 주류는 페이징 기법이다.
가상 메모리는 실제 메모리보다 많아 보이게 하는 기술로, 어떤 프로세스가 실행될 때 메모리에 해당 프로세스 전체가 올라가지 않더라도 실행이 가능하다는 점에 착안하여 고안됨.
빠르고 작은 주기억장치인(RAM) 과 크고 느린 보조기억장치(디스크)와 병합하여, 하나의 크고 빠른 기억장치(가상 메모리)처럼 동작하게 하는 것이다.
가상 메모리를 구현하기 위해서는 MMU 라는 특수 메모리 관리 하드웨어를 갖추고 있어야 함.
MMU는 가상 주소를 물리 주소로 변환하고, 메모리를 보호하는 기능을 수행한다.
가상 주소는 프로세스가 참조하는 메모리 주소이다. 각 프로세스는 독립된 가상 메모리 공간을 가지며, 자신의 메모리 주소를 가상 주소로 인식한다. 프로그램이 실행되는 동안 CPU는 명령어를 수행하며, 참조하는 데이터나 명령어의 위치를 가상 주소를 통해 찾습니다. 그러나 실제 데이터는 물리 메모리에 저장되어 있기 때문에, 이 가상 주소는 물리 주소로 변환되어야만 실제로 메모리 접근이 가능합니다.
물리 주소는 실제 메모리에 저장된 데이터의 주소입니다. CPU가 실제로 데이터를 읽거나 쓸 때에는 가상 주소가 물리 주소로 변환된 후, 물리 주소를 기반으로 메모리에 접근하게 됩니다.
가상 주소는 CPU의 MMU(Memory Management Unit)에 의해 물리 주소로 변환된다. MMU는 가상 주소의 페이지 번호를 이용해 페이지 테이블을 참조하고, 해당 페이지가 메모리의 어느 물리 주소에 있는지 찾아낸다.
가상 주소는 페이지(page) 라는 작은 블록으로 나누어지며, 각 페이지가 물리 메모리 특정 페이지 프레임에 대응된다. MMU는 이 매핑 정보를 담고 있는 페이지 테이블을 참조하여 가상 주소를 물리 주소로 변환한다. 이 떄 가상 주소는 두 부분으로 나뉜다.
Page Number
: 가상 메모리 공간 내의 특정 페이지를 가리킴Offset
: 페이지 내에서의 위치를 나타냄페이지 번호를 통해 찾은 물리 메모리의 프레임에 Offset을 더하여 가상 주소와 실제 물리 주소를 계산한다. 그리고 최종 변환된 물리 주소를 통해 메모리 접근이 이루어 진다.
이 떄 MMU가 요청한 가상 주소에 해당하는 페이지가 물리 메모리에 없을 경우, Page Fault가 발생한다. 이 때 운영체제는 디스크에 있는 해당 페이지를 물리 메모리로 로드하는 과정을 거치게 된다.
Swapping은 메모리에서 사용되지 않는 일부 프로세스의 메모리 데이터를 스왑 공간으로 보내는 것을 말합니다. 이 과정을 통해 메모리 공간을 확보하고, 프로세스를 실행할 수 있는 환경을 마련합니다. Swapping은 가상 메모리 시스템에서 활용되며, 물리 메모리에 더 많은 프로세스를 수용하기 위한 중요한 기법 중 하나입니다.
메모리가 부족한 상황이 발생하게 되면 운영체제는 메모리에 있는 프로세스 중 가장 덜 중요한 프로세스나 현재 실행 중이지 않은 프로세스 (대기상태) 를 선택하여 해당 프로세스의 전체 메모리 혹은 일부 페이지가 하드 디스크의 스왑 공간으로 옮겨집니다. 이를 스왑 아웃 (Swap Out)
이라고 합니다.
스왑 아웃으로 확보된 공간을 새로운 프로세스나 중요한 프로세스가 그 공간을 사용하여 실행됩니다. 이후에 스왑 아웃된 프로세스가 다시 실행되어야 할 때, 해당 프로세스는 디스크에서 스왑 인 (Swap In)
되어 메모리로 다시 로드 됩니다. 이 과정은 동적으로 반복됩니다.
이러한 Swapping은 효율적인 메모리 사용이 가능하게 하고, 물리 메모리가 부족할 때에도 더 많은 프로세스를 실행할 수 있다. 또한 현재 즉시 사용되지 않는 비활성 프로세들을 스왑 아웃하여, 실행 중인 중요한 프로세스가 더 많은 메모리 자원을 활용할 수 있게 한다.
단 디스크는 RAM보다 속도가 느리기 때문에 프로세스를 스왑 인/아웃
하는 데에 상대적으로 시간이 많이 소요된다. 디스크 I/O가 빈번해지면 시스템 성능이 급저하 될 수 있다. 거기에 여러 프로세스가 계속해서 스왑 인/아을 반복하게 되면 시스템의 자원이 모두 Swapping 에만 사용되어 실제 작업이 거의 진행되지 않는 상황인 스레싱 (Thrashing)
이 발생할 수 있다.
페이지 교체는 가상 메모리 시스템에서 페이지 부재 (Page Fault)
가 발생했을 때, 메모리에 새로운 페이지를 불러오기 위해 기존에 메모리에 있던 페이지를 보조 기억장치(디스크)
로 보내고 새 페이지를 메모리에 올리는 과정입니다. 이 떄 페이지 교체 알고리즘
을 통해 어떤 페이지를 교체할 지 결정합니다.
Page Fault가 발생할 때, 페이지 교체가 일어나는데, 이때 어떠한 페이지를 교체하는 지에 대한 결정 방법이다. 어느 알고리즘을 선택하느냐에 따라 시스템 성능에 큰 영향을 끼칠 수 있다.
해당 알고리즘은 단순하게 가장 먼저 메모리에 올라온 페이지를 가장 먼저 교체하는 방식입니다. Queue 형태로 페이지가 관리되며 가장 오래된 페이지가 교체됩니다. 이 방법은 구현이 간단하고 이해하기 쉬우나 오래된 페이지가 자주 사용될 수 있음에도 교체될 가능성이 높기 때문에 Belady의 모순 현상
이 발생할 수도 있다.
Belady의 모순 현상
Page Fault가 자주 발생할 경우 Page Frame 증가시키면, 즉 사용 가능한 메모리를 증가 시키면 직관적으로는 Page Fault 발생 빈도가 감소할 것으로 예상되나, 실제로는 그렇지 않는 현상을 의미한다.
가장 최근에 사용된 적이 없는 페이지를 교체하는 방식입니다. 즉, 가장 오랫동안 사용되지 않은 페이지를 선해 교체합니다. 이는 최근 자주 사용된 페이지를 메모리에 상주하므로 성능적으로 효율적이지만, 페이지 사용 시간을 기록해야 하기 때문에 구현이 상대적으로 복잡하고 오버헤드가 큽니다.
가장 적게 사용된 페이지를 교체하는 방식입니다. 페이지 사용 횟수를 기록하고, 그 중 가장 사용빈도가 낮은 페이지를 교체합니다. 자주 사용 되지 않는 페이지를 교체하여 효율성을 높일 수 있으나, 페이지가 한 번 많이 사용 되었더라도 이후에 사용 되지 않으면 오랫동안 교체되지 않는 문제가 있습니다.
예를 들어 몇 시간 전에 빈번하게 접근하여 사용했던 페이지가 최근에는 접근하는 횟수가 낮은데, 이전에 많이 사용된 페이지기에 교체가 안 이루어지는 것 입니다.
클럭 알고리즘 (Clock Algorithm)
은 페이지 테이블을 원형 큐처럼 다루며, 각 페이지에 대한 참조 비트를 검사합니다. 이 과정은 시계 방향으로 진행된다.
페이지 테이블의 각 페이지는 참조 비트를 가지고 있고, 참조 비트는 아래와 같은 값에 대한 의미를 가진다.
참조 비트
∙ 0
-> 최근에 참조되지 않음
∙ 1
-> 최근에 참조됨
이 때, 페이지 테이블을 원형 큐처럼 순회하는 클럭 핸들러 (Clock Handler)
가 있는데, 이 클럭 핸들러는 현재 검사 중인 페이지의 참조 비트를 검사한다.
참조 비트 -> 1
페이지가 최근에 참조된 페이지로 간주하고, 참조 비트를 0으로 설정 후 클럭 핸들러의 다음 페이지로 이동 시킴. ( 해당 페이지는 교체 대상에서 제외 )
참조 비트 -> 0
페이지가 최근에 참조되지 않는 것으로 간주하며, 이 페이지를 교체 대상으로 선택한다. 페이지를 디스크로 스왑 아웃하고, 새로운 페이지를 메모리에 로드한다.