운영체제 메모리
컴퓨터 내에는 여러 종류의 메모리가 있습니다.
크게는 세 개로 나눌 수 있는데, cpu의 레지스터와 캐시 & 메인메모리 & 보조저장장치hdd, sdd 메모리입니다.
컴퓨터 속 메모리들
레지스터와 캐시, 메인메모리는 매우매우 비쌉니다. 특히 cpu내에 달린 레지스터와 캐시는 속도가 빠른 만큼 비싸죠.
cpu로 계산할 땐, 메인 메모리에 있는 값을 레지스터로 가져와 계산합니다. 계산결과는 다시 메인 메모리에 저장이 됩니다. 그런데, 메인메모리는 레지스터에 비해 상대적으로 너~~무 느립니다. 그래서 레지스터와 메인메모리 사이에 캐시라는 메모리가 존재합니다. 메인메모리에서 레지스터로 옮기기엔 너무 오래 걸릴 것 같을 땐, 필요할 데이터를 미리 가져옵니다. 미리 가져온 데이터도 저장할 곳이 있어야 하겠죠?
그게 바로 캐시입니다.
캐시는 성능의 이유로 여러 개가 있는데, 만약 cpu가 값을 요청해 메인메모리에서 레지스터로 값을 옮겨야 한다면 단계에 따라 가장 속도가 빠른 L1, 없으면 L2, 그 다음은 L3를 확인하고 그것 조차 없다면 메인 메모리를 확인합니다.
우리가 컴퓨터 성능을 체크할 때 보는 L1~L3가 바로 이 개념입니다. L1 -> L2 -> L3로 가는 발전 과정에서 캐시는 크기는 증가시키고 속도는 늦췄습니다. 레지스터가 캐시 안에 있는 값을 찾는데, 캐시의 크기가 작다면 그 값들이 아직 없을 수 있습니다. 그 찾는 과정이 실패하면 성능이 매우 매우 저하됩니다. 이를 캐시 미스라고도 하는데, 이런 캐시 미스가 많을 수록 성능이 더 저하되기 때문에 L3를 가장 크면서 가장 느린 캐시로 두고, 캐시 적중률을 높이는 것이 중요합니다. 가장 용량이 큰 만큼 메모리에서 옮긴 값들이 다 세세하게 있겠죠.
메인 메모리는 모두 알다시피, 폰노이만 구조에서의 모든 프로그램이 실행되기 위해 올라가야만 하는 그 '메모리'입니다. 이 메모리를 관리하는 것이 이번 포스트에서 가장 중요하게 다룰 내용입니다.
hdd,sdd에는 저장되어야할 파일들이 있습니다. 위의 레지스터, 캐쉬, 메모리를 저장메모리로 쓰기엔 값이 너무 비싸기 때문에 가장 저렴하고 전원이 공급되지 않아도 데이터가 지워지지 않는 이 메모리에 정보를 모두 저장합니다.
메인 메모리
메모리에서 가장 중요한 것은 무엇보다 메인 메모리일 것입니다. 폰 노이만 구조에 입각하여 모든 프로그램을 실행시키기 위해선, 메모리에 올려야 합니다. 점점 프로그램이 복잡해질 수록 메모리를 관리하는 일이 힘들어집니다. 운영체제도 관리해야하고, 프로그램도 관리해야하고, 이런 메모리를 관리하는 것은 메모리 관리 시스템(MMS)가 관리합니다.
메모리 관리자는 가져오기, 배치, 재배치 등의 작업을 하게 됩니다.
프로세스와 데이터를 메모리를 가져오는 작업, 앞으로 필요할 것 같은 데이터 또한 미리 가져옵니다. 또 프로세스와 데이터를 메모리 어떤 부분에 올려놓을 건지도 결정해야합니다. 가져온 메모리를 어떻게 크기를 할 건지, 어떤 위치를 놓을 건지에 따라 메모리 관리가 달라지기 때문에 이 배치 작업은 매우 중요합니다. 새 프로세스를 가져와야 하는데 메모리가 다 찼다면 메모리의 프로세스를 하드웨어에도 다시 옮겨놓는 작업을 해야합니다. 이 재배치 작업 또한 메모리 관리 시스템이 해줘야합니다.
후에도 다루지만, 배치 정책에서는 메모리를 같은 크기로 자르는 것을 페이징이라고 하며, 프로세스 크기에 맞춰 자르는 것을 세그먼테이션이라 부릅니다. 이 두가지 방법은 각자 장단점이 있으며, 메모리 효율 또한 다릅니다. 그러므로 이 두 가지 방법을 상황에 맞게 적절히 쓰는 것이 MMS가 할 일 입니다.
재배치 정책에서는 메모리가 꽉 찼을 때 어떤 프로세스를 내보낼 지 결정하는데, 앞으로 쓰지 않을 프로세스를 찾아내서 내보내는 교체 알고리즘이 쓰입니다.
메모리 주소
메모리에 접근할 때는 주소를 이용합니다. 그러므로 메모리의 주소를 이해하는 것은 매우 중요합니다.
운영체제는 메모리 관리를 위해 1바이트 크기로 구역을 나누고 숫자를 매겼고, 이 숫자는 주소라고 부릅니다.
0x1 | 0x2 | 0x3 | ... | ... | ... | 0xfff |
32bit cpu 64 bit cpu
메모리 얘기 실컷하다가 갑자기 cpu가 나온다고요? 당황스럽지만, cpu의 비트는 메모리 주소 공가의 크기와 연관이 있습니다.
CPU의 비트는 한 번에 다룰 수 있는 데이터의 최대 크기를 의미합니다. 32bit CPU는 한 번에 다룰 수 있는 데이터의 최대 크기가 32bit라는 뜻이며, 레지스터 크기, 산술 논리 연산장치, 대역폭, 대역폭을 통해 한 번에 옮겨지는 데이터의 크기도 모두 32bit입니다. 32bit의 메모리 주소 레지스터 크기도 32bit이므로, 표현할 수 있는 메모리 주소의 범위가 2의 32승 b, 4GB입니다. 그러므로 32bit CPU컴퓨터는 메모리를 최대 4GB까지 이용할 수 있다는 뜻입니다. 64bit는 64bit만큼 다 다룰 수 있고 32bit보다 한 번에 처리할 수 있는 양이 많기에 속도 또한 매우 빠릅니다. 메모리 주소 공간은 2의 64승으로 거의 무한대에 가까운 메모리를 사용할 수 있습니다.
물리주소와 논리주소
이렇게 32bit CPU든 64bit CPU든, 메모리를 컴퓨터에 연결하면 0번지부터 시작하는 주소공간이 있는데, 이를 물리 주소 공간이라 부릅니다. 물리 주소 공간은 하드웨어 입장의 주소 공간으로 컴퓨터마다 그 크기가 다릅니다, 이와 다르게 사용자 관점에서 본 주소공간을 논리 주소 공간이라고 부릅니다. 이 둘의 차이는 후술할 것입니다. 사용자는 물리 주소는 몰라도 논리 주소로 물리 주소에 접근이 가능합니다.
절대주소와 상대 주소
메모리
메모리에는 운영체제와 수 많은 프로세스가 올라갑니다. 그 중에 운영체제는 매우 특별하기 때문에 운영체제의 공간은 따로 존재합니다. 사용자의 프로세스가 운영체제를 침범하면 안되기 때문에, 하드웨어적으로 운영체제와 사용자 공간을 나누는 경계 레지스터를 만들었습니다.
메모리 관리자는 사용자 프로세스가 경계 레지스터의 값을 벗어나면 그 프로세스를 강제 종료시킬 수 있습니다.
개발자가 개발을 할 때 프로그램이 실행될 주소를 신경쓰며 개발하는 것을 보셨나요? 주소는 상관없이 그저 코드로 개발만 하면 되는데요, 이는 컴파일러가 컴파일을 할 때 메모리가 0번지에서부터 실행한다고 가정하기 때문입니다.
절대주소와 상대주소
개발자의 프로그램을 실행시켜 메모리의 사용공간 4000번지에 올라갔다고 칩시다. 컴파일러는 4000번지라고 따로 생각하지 않고 0번지라고 그저 가정만 할 뿐입니다.
실제 프로그램이 올라간 주소는 4000번지이고, 이는 메모리관리자가 바라본 절대 주소입니다. 이 절대 주소를 물리 주소 공간이라 합니다. 램에 실제로 꼽힌 프로그램의 주소는 4000번지니까요.
하지만 사용자가 쓰는 컴파일러는 프로그램의 주소를 0번지라고 했습니다. 만약 운영체제가 갑자기 3999번지까지 쓰다가 4001번지까지 쓰고 싶다고 하면, 물리주소로 컴파일러가 프로그램의 주소를 4000번지라고 했다면 큰 혼란이 야기될 것입니다. 그런 혼란을 하기 위해 그냥 컴파일러는 0번지라고 가정하는 것입니다. 그래서 사용자가 바라보는 주소인 상대 주소를 논리 주소 공간이라 합니다.
상대 주소를 절대 주소로 변환하는 과정
상재 주소를 사용시에는 상대 주소는 물리 주소, 절대 주소로 변환해야겠죠? 이 변환 작업은 메모리 관리자의 일입니다.
위 그림에 있는 재배치 레지스터는 프로그램의 시작 주소가 저장되어 있습니다. 앞에 프로그램이 운영체제 뿐이라면, 운영체제의 크기만큼 재배치 레지스터에 들어가있고, 그 주소 다음에 바로 상대주소를 넣으면 됩니다. 이렇게 접근하게 되면 프로그래밍도 편해질 뿐만 아니라, 앞의 프로그램의 시작영역, 끝영역이 바뀌어도 재배치 레지스터만 변경하면 되기 때문에 메모리 관리가 굉장히 쉬워집니다.
메모리 할당 방식 - 유니프로그래밍
메모리 오버레이 & 스왑
과거에 메모리가 매우 비쌌을 때, 컴퓨터에 큰 메모리를 사용할 수 없었습니다. 2GB짜리인데, 8GB짜리 프로그램이 메모리에 올라가려면 어떻게 해야했을 까요?
큰 프로그램을 메모리에 올릴 수 있도록 크기를 잘라서 당장 실행시킬 부분만 메모리에 올리고 나머지는 하드디스크에 저장하는 기법을
메모리 오버레이라고 부릅니다. 메모리 오버레이를 통해 큰 프로그램을 컴퓨터 내부에 실행시키는 것이지요.
큰 프로그램을 작게 나누어 일부만 실행하고 나머지는 하드디스크에 저장하는데, 정확히는 하드디스크의 스왑영역에 프로그램이 저장됩니다.
스왑은 말 뜻 그대로 스왑영역에 있는 데이터 일부를 메모리로, 메모리에 있는 데이터를 스왑영역에 옮기는 것입니다. 이렇게 된다면 사용자는 메모리가 8GB이상인것처럼 느끼는 것이지요. 하지만 스왑과정을 행해야 하기 때문에 실제 메모리가 8GB이상인 것보다는 한참 느릴 수 밖에 없습니다.
뭐, 단일 프로그래밍이 가능했던 시기는 이런 방법을 통해 메모리가 큰 프로그램을 실행시킬 수 있었습니다.
하지만 요즘은 어떻죠? 수 많은 여러 개의 프로세스가 메모리에 올라옵니다.
메모리 할당 방식 - 멀티 프로그래밍
하나의 프로그램만 취급하는 유니프로그래밍도 나름 복잡한데, 수 많은 프로그램을 다루는 멀티 프로그래밍은 정말 복잡하다 여겨집니다.
메모리의 크기를 나누는 방식은 2가지로 나뉘어 집니다.
프로세스의 크기에 따라 메모리를 나누는, 가변 분할 방식과 프로세스 크기 상관없이 메모리를 정해진 크기로 나누는 고정 분할 방식입니다.
가변분할방식과 고정분할방식
가변 분할 방식
가변 분할 방식은 그림과 같이 프로세스 크기에 따라 메모리를 나눕니다. 한 프로세스가 메모리에 연속된 공간에 할당되기 때문에 '연속 메모리 할당'이라고도 부릅니다. 또 세그멘테이션이라고도 부릅니다.
고정 분할 방식
고정 분할 방식은 페이징으로도 불리며, 프로세스 크기와 상관없이 메모리를 '정해진 크기'로 나눕니다. 그 정해진 크기가 2mb로 정해지면, 그 프로세스가 어떤 크기이든 2mb씩 잘라지게 됩니다. 그러면 5mb는 2mb씩 잘려, 3개로 나누어지고, 3mb는 2mb+1mb , 1mb는 2mb를 할당받아 1mb는 빈공간으로 남습니다. (듣기만 해도 좀,, 비효율적이네요) 한 프로세스가 메모리에 분산되어 할당되기 때문에 비연속 메모리 할당이라 부릅니다.
가변분할방식과 고전분할방식의 장단점
가변 분할 방식, 고정 분할 방식은 각각 장단점이 명확합니다.
가변 분할 방식의 장점은 프로세스가 하나로 처리되어 연속된 공간에 배치된다는 점입니다. 고정 분할 방식의 단점인 내부단편화 문제가 없습니다.
외부 단편화
단점으로는 외부 단편화가 발생합니다. 외부 단편화 문제는 가변 분할 방식이기 때문에 생겨납니다.
그림에서 프로세스 18kb와 17kb의 역할이 끝났다 칩니다. 19kb의 프로세스가 새로 메모리에 들어가고 싶어합니다. 무려 18kb와 17kb가 빠져나가 35kb의 크기가 메모리에 있지만, 18kb와 17kb가 비면서 19kb가 들어갈 곳은 없기 때문에 19kb의 프로세스는 메모리 안으로 들어가지 못합니다. 연속공간이 아니라서 새로운 프로세스에게 할당이 불가한 것을 외부단편화 문제라고 부릅니다.
고정 분할 방식의 장점으로는 구현이 간단하고 오버헤드가 작다는 점이 있습니다.
단점으로는 작은 프로세스도 큰 영역에 할당되기에 공간이 낭비되는 내부단편화가 발생합니다. 아까 1mb여도 할당된 메모리가 2mb면 메모리를 할당받고 남은 1mb는 그냥 빈공간으로 남는다고 하였죠, 이 문제가 바로 내부단편화입니다.
"오늘날,
운영체제"는 가변 분할 방식과 고정 분할 방식을 혼합하여 장점을 늘리고 단점을 줄이는 방식을 가져갑니다.
외부단편화는 외부단편화가 발생한 공간을 합쳐주는 '조각모음'을 통해 문제를 어느정도 해결할 수는 있습니다. 하지만 조각모음을 하려면 현재 메모리에 실행되는 프로세스의 작업을 중지하며, 메모리 공간을 이동시키는 작업 또한 해야하기 때문에 오버헤드가 발생할 수 있습니다.
내부단편화의 문제점을 해결하는 방법은 거의 없습니다. 분할되는 크기를 조절해서 내부단편화를 최소화를 하는 수 밖에 없습니다.
버디시스템(가변분할방식+고정분할방식)
가변분할방식과 고정분할방식의 단점을 최소화한 버디시스템이 있습니다. 사실, 버디 시스템은 가변 분할 방식입니다. 하지만 고정 분할 방식과 유사합니다.
버디시스템은 2의 승수로 메모리를 분할해 할당하는 방식입니다. 메모리 크기가 2048 바이트라면 2의 11승이겠죠? 크기가 500바이트인 프로세스가 메모리 할당을 원한다면, 500바이트와 가까워 질 때 까지 값을 나눕니다.
2048 % 2 = 1024
1024 % 2 = 512
512 % 2 = 256
...
이렇게 나눕니다. 그러면, 256바이트, 516바이트 중 500바이트가 할당이 되는 크기를 찾습니다. 512바이트가 그 크기겠네요. 내부단편화가 발생하지만 12바이트 정도밖에 나지 않습니다. 이렇게 2의 승수로 나누는 방법은 근접한 메모리 공간을 합치기도 쉽고, 조각모음보다 훨씬 간단합니다.
버디시스템을 이용하면 프로세스 크기에 따라 할당되는 메모리 크기가 달라지며, 외부단편화를 방지키 위한 메모리 공간 확보가 간단해집니다. 고정분할처럼 내부단편화가 살짝은 발생하지만 원래에 비하면 많은 공간 낭비도 발생하지 않기에 큰 장점이 됩니다. 가변 분할 보다는 더 효과적이지만, 고정 분할 방식이 메모리 관리 측에서 단순하기 때문에 버디 시스템보다는 고정 분할 방식이 선호될 때도 많습니다.
이번 포스팅에서는 컴퓨터 내부에 있는 메모리의 종류와, 메인 메모리에 대해 알아보았습니다.
메인 메모리는 프로그램이 무조건 거쳐야 하는 공간으로 매우 매우 cpu다음으로 중요한 부품입니다. 과거에 비해 프로그램 크기도 커지고, 동시에 쓰이는 것도 많아지면서 이를 어떻게 효율적으로 쓸지가 중요해졌습니다. 그래서 메모리 관리자가 생겨, 메모리를 어떻게하면 효과적으로 쓸 지 연구가 많이 되었습니다.
프로그램이 실행될 때, 메모리 공간, 주소 '어디에' 들어가는 문제가 중요해졌기 때문에 주소 자체가 생성되며, 그 주소를 효율적으로 쓰기 위해 절대주소/ 상대주소라는 개념도 생기게 되었습니다. 프로그램을 더 쉽게 생성하기 위해 논리주소공간이 생겨 0번지에 들어가게 하였고, 메모리 관리자가 실제로 이 주소를 정확한 물리 공간인 절대 주소에 변환하여 넣습니다. 그렇게 되니 다른 프로그램과 겹쳐져 충돌할 일이 사라집니다.
프로그램이 메모리에 들어올 때도 '어떻게' 들어오는 지가 중요합니다. 그래서, 가변 분할 방식 / 고정 분할 방식들이 고안됩니다.
프로그램의 크기 대로 메모리에 넣으니, 그 프로그램들이 다 쓰고 나가면 크기가 맞지 않아 들어가고 싶어도 들어가지 못하는 외부 단편화 문제가 생겨버립니다. 남는 크기는 많은데, 크기가 맞지 않는다라는 이유로 사용이 안되니 이래저래 불편할 수 밖에 없습니다. (가변분할)
그래서 고정으로 특정 크기대로 끊어서 프로그램을 넣으니, 이번에는 크기가 작은 프로그램도 특정 크기대로 할당받아 남아 노는 문제가 생깁니다.(고정분할) 그래서, 이 둘의 문제점을 합쳐 2의 승수로 나눠서 크기에 맞춰 나눠지는 방법이 생깁니다.(버디) 이는 남아 노는 분제인 내부 단편화 문제를 최소화 시키긴 하였으나, 2의 승수를 또 구해야한다는 점이 복잡하기 때문에 고정 분할 방식이 많이 쓰입니다.
'CS' 카테고리의 다른 글
OS | 교착상태, 데드락 (5) | 2025.03.26 |
---|---|
OS | 프로세스 동기화, 통신, 공유자원, 임계구역 (0) | 2025.03.26 |
OS | CPU 스케줄러, CPU 스케줄링 알고리즘 (0) | 2025.03.26 |
OS | 프로세스와 스레드 (0) | 2025.03.26 |
OS | 운영체제 컴퓨터의 구조, 특성 (0) | 2025.03.26 |