본문 바로가기

CS 전공수업/컴퓨터 운영체제

[OS] 메모리, 캐시, 운영체제의 메모리 관리

기본적으로 컴퓨터 구조를 다룰 때, CPU의 ALU가 연산을 시전하는 부분이라면 그 일련의 과정에 있어서 데이터를 저장하고 빼내는 등의, 일종의 창고 역할을 하는 부분이 필요한데, 그걸 넓은 의미에서의 메모리라고 한다.

 

 

메모리의 종류

 

종류로는 레지스터, 캐시(L1, L2, L3), RAM(주기억장치), 디스크(보조기억장치) 등이 있다. 저 순서대로 오른쪽으로 갈수록 더 많은 양의 데이터를 저장할 수 있지만, CPU로부터의 접근성이 떨어지고, 그렇기 때문에 가격도 싸진다.

참고로 레지스터와 캐시의 일부(1은 항상, 2는 때때로)는 CPU 내부에 위치해 있다. 접근성이 최고인 셈. 각각을 알아보면,

 

1 레지스터: CPU가 즉시 사용할 수 있는 데이터를 저장하는 공간.

2 캐시 메모리: CPU가 매우 빠르기 때문에 CPU와 주 메모리(RAM) 간의 속도 차이가 있다. 그러면 CPU는 메모리에서 날아오는 데이터를 기다리는 동안 놀아야 되기 때문에 비효율적이다. 이걸 최대한 방지하기 위해 캐시가 있다. 캐시는 한마디로, 주메모리에서 자주 사용되는 (혹은 사용될 법한) 데이터들을 선별하여 저장해두는 것이다. 캐시 내부에서도 L1, L2, L3 등의 차등이 있는데, 역시나 숫자가 커질수록 덩치는 크지만 속도가 느리다. 이걸 캐시 메모리라고 부르고, 그걸 동사로 표현한 게 캐싱(caching)이다.

메인까지 가기가 너무 멀어서 중간 지점에 "캐싱"한다는 표현으로 쓴다. 그 표현을 활용하면, CPU로부터 RAM의 거리가 멀어서 cache memory를 사용하여 caching한다 라고 할 수 있겠다.

3 주 기억장치: RAM이라고도 불리는 이 주기억장치는, 메모리들 중 가장 메인 격의 녀석이다. 그러니까 CPU와의 메인 파트너고, 캐시와 디스크는 서로 다른 목적으로 이를 도와주기 위한 보조적 역할이라고 생각하면 된다. 주기억장치까지의 메모리들은 모두 휘발성이라는 특징이 있다. 즉, 프로그램이 실행되는 동안만 임시로 저장하고, 프로그램이 끝나는 순간 데이터가 사라진다. 이게 가장 우두머리기 때문에 가끔 RAM 그 자체만 "메모리"라고 부르기도 한다. 좁은 의미에서의 메모리.

4 보조 기억장치: Disk라고도 불리는데, RAM이 용량이 적어 모든 데이터를 저장할 수 없기 때문에, 모든 데이터를 저장할 수 있도록 위치한 메모리다. 지방 hub처럼, 지방이라 가격도 싸고 덩치도 크지만 서울(CPU)에서의 접근성이 매우 안 좋다.

 

캐싱

그러니까 메인 메모리(그게 뭐가 됐든간에)에 접근을 해야하는데 그게 시간이 오래 걸려서, 그 중 자주 쓰일만한 데이터들을 골라서 사전에 더 가까운 곳에 모아두는 것을 캐싱이라고 한다고 했다.

 

캐시 히트와 캐시미스: 캐싱한 데이터가, 실제로 쓰일 수도 있고 안 쓰일 수도 있다. CPU에서 어떤 데이터가 필요해서 일차적으로 캐시를 봤는데 만약 그 값이 거기에 있다? 그러면 캐시 히트인거다. 그러면 그 값을 빼서 쓰면 되고 RAM까지 갈 필요가 없다. 만약 없다면? 캐시 미스라고 하고, RAM까지 가서 공수해와야 한다.

그러니까 잘된 캐싱은, 캐시 히트의 비율이 높은 캐싱이다.

 

그러면 자주 쓰일만한 데이터는 어떤 기준으로 고를까? 기준은 두 가지다: 시간 지역성, 공간 지역성.

 

1 시간 지역성: 가장 최근에 사용한 데이터는 앞으로도 또 쓰일거라는 추론을 통해, 가장 최근에 쓰인 녀석을 뽑는 거다.

2 공간 지역성: 최근에 쓴 데이터가 속한, 그 근처 데이터들을 모조리 뽑는 거다.

 

 

이런 지역성들을 활용해서, 실제로 쓰이는 알고리즘을 캐시 매핑이라고 하는데, 그 종류는 다음과 같다.

 

1 직접 매핑 Direct Mapping: 메인 메모리의 각 블록은 고정된 하나의 캐시 블록에 매핑됨. 장점은 단순하여 처리가 빠르다는 거지만, 단점은 충돌 발생이 잦다는 것이다.

 

ex)  캐시가 0, 1, 2, 3의 공간이 있고 메인 메모리에 0, 1, 2, 3, ... 10, 11의 데이터가 있을 때, 메인의 데이터를 4로 나눈 것으로 캐싱한다고 하면, 캐시의 0에는 0, 4, 8, 1에는 1, 5, 9 이런 식으로 여러 개의 데이터가 캐시에 포함되게 된다. 이러면 메인 메모리의 0, 4, 8이 캐시의 0 블록에 매핑되어 충돌이 발생하는 식으로 충돌이 자주 발생한다.

 

2 완전 연관 매핑 Fully Associative Mapping: 순서를 일치시키지 않고 관련 있는 캐시와 메모리를 매핑 - 충돌 적지만 구현하기도 힘들고 모든 블록을 탐색해야 하므로 오래 걸린다. 캐시 히트율이 높음.

 

3 부분 연관 매핑 Set Associative Mapping: 완전 연관 매핑과 유사하지만, 특정 집합 (set) 내의 여러 캐시 블록에 매핑될 수 있음. 여러 집합으로 나뉘며, 각 집합은 여러 캐시 블록으로 구성됨. 완전 연관 매핑 정도는 아니지만 캐시 충돌이 덜하고, 히트율도 꽤 높다.

 

=> 결론적으로 직접 매핑은 구현 쉽지만 성능상 너무 안 좋기 때문에 (충돌 많고, 고로 히트율 낮음) 안 쓰고, 연관 매핑은 성능상 매우 좋지만 알고리즘 구현 어렵고, 실행하면 모든 값과 비교해야 하므로 시간이 너무 오래 걸려 덜 쓰고, 결과적으로 적당히 성능 나오고 구현도 적당한 Set Associative Mapping을 다들 주로 활용한다.

 

웹 브라우저의 캐시

소프트웨어적인 대표적인 캐시로는 웹 브라우저의 작은 저장소 쿠키, 로컬 스토리지, 세션 스토리지 이렇게 있음.

모두 키-값 형태로 데이터를 저장함.

 

1 쿠키: 만료기한을 지정함. 4KB까지 데이터를 저장할 수 있고, HTTPOnly, Secure 플래그로 보안 강화할 수 있음. 쿠키 설정 시에는 document.cookie로 쿠키를 볼 수 없게 httponly 옵션을 거는 것이 중요. 쿠키는 동일한 도메인의 모든 요청에 자동으로 전송됨. 디스크에 저장됨.

예시로 사용자 언어, 테마 설정, 광고를 위한 사용자 행동 추적, 로그인 상태 등 세션 관리 등. document.cookie;

2 로컬 스토리지: 브라우저에 영구적으로 저장할 수 있는 클라이언트 측 저장소. 도메인 단위로 데이터 저장. 도메인 당 5~10MB까지 가능. 디스크에 저장됨.

예시로 사용자 설정, 즐겨찾기, 장바구니 데이터 등. localStorage.setItem...;

3 세션 스토리지: 웹 브라우저 세션이 활성화된 동안 데이터를 저장하는 클라이언트 저장소. 만료기한 없지만, 브라우저 닫히면 없어짐. 역시나 5~10MB. 브라우저 메모리에 저장됨.

예시로 폼 데이터 등의 일시적 사용자 입력, 세션 상태 관리 등. windowStorage.setItem,..;

 

* 추가로 DB에서도 캐싱이 일어난다. 메인 DB 위에 redis를 캐시로 얹는다.

 

운영체제의 메모리 관리 - virtual memory 개념 등장

메모리가 한계가 있기 때문에 운영체제에게는 이 메모리를 잘 관리해서 극한으로 활용할 수 있게 하는 미션이 있다.

 

가상 메모리 virtual memory

 

 

말 그대로 메모리를 가상화하는 것.

실제 이용가능한 메모리는 한정되어 있지만 이를 추상화하여 유저들로 하여금 매우 큰 메모리로 보이게 만듦.

 

 

1 가상 주소 공간 Virtual Address Space

 

각 프로세스는 고유한 가상 주소 공간을 가짐. 프로세스는 실제 물리적 메모리 주소를 알 필요없이 가상 주소를 사용하여 메모리에 접근함. OS의 주소 변환 유닛(MMU, Memory Management Unit)에 의해 가상 주소를 물리적 주소로 변환함.

 

*TLB Translation Lookaside Buffer: 페이지 테이블을 위한 캐시

 

 

2 페이지 Pages

 

가상 메모리의 단위는 고정된 크기의 페이지. 하나에 4KB.

물리적 메모리도 프레임이라는 블록으로 나뉨.

 

 

3 페이지 테이블 Page Table

 

MMU가 매핑을 시킨다면, page table이 가상 주소와 물리적 주소 간(RAM 과 디스크 모두)의 매핑 정보를 저장.

각 프로세스는 고유한 페이지 테이블을 가짐. 꼭 한 페이지는 아님. 여러 페이지일 수 있음.

 

 

4 페이지 폴트 Page Fault - 약간 캐시미스같은 느낌.

 

(1) 페이지 폴트: 프로세스가 특정 가상 주소에 접근했는데, 해당 페이지가 RAM에 존재하지 않음.

(2) CPU는 페이지 폴트를 감지하고, 트랩을 걸어 OS에 알림.

(3) OS는 CPU를 일시 중지시키고 페이지 폴트 핸들러를 호출함.

(4) 페이지 테이블 엔트리를 통해 해당 페이지가 물리적 메모리에 있는지, 아니면 디스크에 있는지 확인함.

(5) 만약 해당 데이터가 RAM에 없고 디스크에 있다면, 해당 값을 RAM으로 로드함.

(6) 새로운 페이지를 로드할 공간이 RAM에 없다면, 안 쓰는 부분을 일부 스왑 아웃하여 공간을 확보함 - 스와핑.

(7) 새로운 페이지 테이블에 기록하여 새로운 매핑을 설정함 - 즉, 이제는 페이지 폴트가 발생하지 않음.

 

 

=> 이를 통해 효율적인 메모리 사용 메모리 보호(프로세스 별로 고유한 가상 공간을 할당하므로 하나가 다른 하나를 침범하지 못함) 등의 장점이 있지만, 성능 오버헤드를 초래할 수 있다는 것구현이 어렵고 하드웨어의 많은 지원이 필요하다는 단점이 있다.

 

Thrashing

Thrashing = 메모리 페이지 폴트율이 높아 개판이 되어가는 상황을 의미. 

 

가상화를 통해서 여러개의 프로세스가 메모리에 올라갈 수 있게 되었지만, 동시에 너무 많은 프로레스가 올라가게 되면 자연스레 스와핑이 많이 일어나고 그렇기 때문에 CPU 이용률이 낮아지게 됨. CPU 이용률을 척도로 삼는 OS는 "CPU 한가하노?"라고 생각한 나머지 더 많은 프로세스를 메모리에 올리게 되는, 악순환이 반복되게 된다.

 

* 과정을 잘 생각해보면, CPU 활용도가 낮아짐과 동시에 thrashing이 생기는 건 말이 안된다. 어떤 그림들은 그렇게 표현했던데, thrashing은 그 이후 어느 시점부터 발생한다고 생각하면 된다.

 

이렇게 병이 있으면, 이걸 해결하는 약도 알아야 한다. 약의 종류는 몇가지가 있다.

 

1 단순하게 물리적 메모리를 늘리기. 페이지 폴트를 줄임.

2 HDD를 사용하는 중이라면 SSD로 교체하기.

3 작업 세트 working set 활용하기: 프로세스의 과거 사용 이력 (locality) 을 통해 결정된 페이지 집합을 미리 메모리에 로드하는 것. 그러니까 이전에 썼던 흔적을 토대로 만든 메모리 환경을 그대로 구현해주는 것. 

4 Page Fault Frequency: 페이지 폴트 빈도를 조절하는 방법으로, 상한선과 하한선을 만드는 방법. 상한선에 도달하면 프레임을 늘리고 하한선에 도달하면 프레임을 줄이는 것.

 

메모리 할당 Memory Allocation

메모리에 프로그램을 할당할 때는 시작 메모리 위치, 메모리 할당 크기를 기반으로 할당하는데, 연속과 불연속 할당으로 나눔. 기존의 메모리 사용 마지막 주소에 바로 얹으면 연속 할당, 그게 아니면 불연속 할당. 연속할당이 계산이 쉽지만, 메모리 사용의 유연성이 떨어지고, 외부 단편화가 발생할 수 있음. 불연속 할당은 필연적으로 hole이 발생할 수밖에 없음.

 

* 외부 단편화: 배정한 메모리보다 프로세스의 실사용 메모리가 더 많은 경우

* 내부 단편화: 배정을 너무 과하게 많이 해서 프로세스가 다 쓰고도 메모리 공간이 한참 낭비되는 경우

 

또한 고정 분할의 경우 사전에 메모리를 분할하는 방식으로, 융통성 없고 보수적으로 배정하므로 내부 단편화 발생함.

가변 분할의 경우 매 시점 프로그램의 크기에 맞게 동적으로 메모리를 나눠 사용하는데, 실시간으로 배정하지만 시간 차가 있기 때문에 외부 단편화가 발생할 가능성이 있음.

 

불연속 할당의 방법에는 몇 가지가 있다.

 

1 페이징: 동일한 크기의 페이지 단위로 나누어 메모리의 서로 다른 윛치에 프로세스를 할당함. 홀의 크기는 균일하지만 계산이 어렵다고 함.

2 세그멘테이션: 막무가내로 사이즈를 정해서 페이지 단위로 나누는 게 아니라 세그먼트 단위로 나누는 방식. 공유와 보안 측면에서 강점을 가지지만 홀 크기가 균일하지 않음.

3 페이지드 세그멘테이션: 우선 세그먼트로 나눈 다음에 동일한 크기의 페이지 단위로 나눔.

 

페이지 교체 알고리즘

메모리는 한정되어 있기 때문에 스와핑이 많이 일어남. 이걸 최대한 방지하기 위해 몇 가지를 쓰는데,

FIFO: First In First Out, LRU: Least Recently Used, NUR: Not Used Recently, LFU: Least Frequently Used

'CS 전공수업 > 컴퓨터 운영체제' 카테고리의 다른 글

[OS] 운영체제 꼬리물기 질문 대비  (2) 2024.07.24
[OS] 프로세스 & 쓰레드  (11) 2024.07.23
[OS] 운영체제 기본  (0) 2024.07.14