CS study - 운영체제 - 1
3장 운영체제 - 1
사용자가 컴퓨터를 쉽게 다루게 해주는 인터페이스로 한정된 메모리나 시스템 자원을 효율적으로 분배하는 역할을 하며 유사한것으로 소프트웨어를 추가설치 할 수 없는 펌웨어(firmware)가 있습니다.
1-1 운영체제의 역할과 구조
- CPU 스케줄링과 프로세스 관리 : CPU 소유권을 어떤 프로세스에 할당할지, 프로세스의 생성과 삭제, 자원 할당 및 반환을 관리합니다.
- 메모리 관리 : 한정된 메모리를 어떤 프로세스에 얼만큼 할당하는지 관리합니다.
- 디스크 파일 관리 : 디스크 파일을 어떤방법으로 보관할지 관리합니다.
- I/O 디바이스 관리 : 입출력 기기들의 데이터를 주고 받는 것을 관리합니다.
운영체제의 구조
- GUI : 사용자가 전자장치와 상호 작용할 수 있도록하는 사용자 인터페이스의 형태, 단순 명령어 창이 아닌 아이콘을 마우스로 클릭하는 단순한 동작으로 컴퓨터와 상호 작용할 수 있도록 해준다.
- 드라이버 : 하드웨어를 제어하기 위한 소프트웨어
- CUI : 그래픽이 아닌 명령어로 처리하는 인터페이스
시스템 콜 이란 운영체제가 커널에 접근하기 위한 인터페이스로 유저 프로그램이 운영체제의 서비스를 받기 위해 커널 함수를 호출할 때 사용됩니다.
- I/O 요청 : 입출력 함수, 데이터베이스, 네트워크, 파일 접근 등에 관한 일
- 드라이버 : 하드웨어를 제어하기 위한 소프트웨어
프로세스와 스레드에서 운영체제로 요청을 보낼 때 시스템 콜이라는 인터페이스와 커널을 거쳐 운영체제에 전달됩니다. 이런 시스템콜은 하나의 추상화 계층으로 네트워크 통신이나 데이터베이스와 같은 낮은 레벨의 영역 처리에 대한 부분을 신경쓰지 않고 프로그램을 구현할 수 있다는 장점이 있습니다.
modebit
시스템콜이 작동될 때 유저모드와 커널모드를 구분하는 플래그로 쓰이는 변수입니다. 0은 커널 모드, 1은 유저 모드라고 설정됩니다.
- 유저 모드 : 유저가 접근할 수 있는 영역을 제한적으로 두며 컴퓨터의 자원에 함부로 침범하지 못하는 모드
- 커널 모드 : 모든 컴퓨터 자원에 접근할 수 있는 모드
- 커널 : 운영체제의 핵심 부분이자 시스템콜 인터페이스를 제공하며 보안, 메모리, 프로세스, 파일시스템, IO디바이스와 요청 관리등 중추적인 역할을 한다.
1-2 컴퓨터의 요소
CPU, DMA 컨트롤러, 메모리, 타이머, 디바이스 컨트롤러 등으로 이뤄져있습니다.
CPU
Central Processing Unit은 산술논리연산장치, 제어장치, 레지스터로 구성되어 있는 컴퓨터 장치를 말하며, 인터럽트에 의해 단순히 메모리에 존재하는 명령어를 해석해서 실행하는 일꾼의 역할입니다.
- 제어장치 : Control Unit 은 프로세스 조작을 지시하는 CPU의 부품으로 입출력 장치 간 통신을 제어하고 명령어들을 읽고 해석하며 데이터 처리를 위한 순서를 결정합니다.
- 레지스터 : CPU안에 있는 임시기억장치로 CPU와 직접 연결되어 있어 연산속도가 메모리보다 빠릅니다. CPU는 자체적으로 데이터를 저장할 방법이 없기때문에 레지스터를 거쳐 데이터를 전달합니다.
- 산술논리연산장치 : Arithmetic Logic Unit 는 덧셈, 뺄셈등의 산술 연산과 배타적 논리합, 논리곱같은 연산을 하는 디지털 회로입니다.
CPU의 연산처리
- 제어장치가 메모리에 계산할 값을 로드하고 레지스터에도 로드합니다.
- 제어장치가 레지스터에 있는 값을 계산하라고 산술논리연산장치에 명령합니다.
- 제어장치가 계산된 값을 다시 ‘레지스터에서 메모리로’ 계산한 값을 저장합니다.
인터럽트
어떤 신호가 들어왔을 때 CPU를 잠깐 정지시키는 것을 말하며 디바이스, 산술연산, 프로세스 오류등 다양한 이유로 발생합니다. 인터럽트가 발생되면 핸들러 함수가 있는 인터럽트 벡터로 가서 핸들러 함수가 실행되며, 인터럽트 간에는 우선순위가 있고 우선순위에 따라 실행합니다. 종류로는 하드웨어, 소프트웨어 인터럽트가 있습니다.
- 핸들러 함수 : 하드웨어 인터럽트가 발생했을 때 이를 핸들링하기 위한 함수로 커널 내부의 IRQ(Interrupt Request)를 통해 호출되며 request_irq()를 통해 인터럽트 핸들러 함수를 등록할 수 있다. 인터럽트 핸들러 함수는 인터럽트를 처리하고, 필요한 경우 다른 함수나 스레드를 호출하여 추가적인 처리를 할 수 있으며 빠르게 실행되야 하므로 최소한의 코드만 포함해야 합니다. 또한 다른 핸들러 함수나 커널 코드와 동시에 실행되지 않도록 보호되어야 합니다.
- IRQ : Interrupt Request 는 CPU가 어떤 작업을 수행하고 있는 중에 다른 작업을 수행하도록 강제 전환시키는 기능입니다. 이를 통해 시스템의 반응성을 향상시키고, 시스템 리소스를 효율적으로 사용할 수 있습니다. 하드웨어 IRQ는 주로 입출력 장치나 타이머등이 발생시키며 소프트웨어는 시스템콜이나 예외상황등이 발생시킵니다.
하드웨어 인터럽트
키보드나 마우스등 디바이스를 연결하거나 네트워크 패킷의 수신, 디스크의 입출력등 하드웨어에서 발생하는 신호에 의해 발생하는 인터럽트를 의미하며, 하드웨어 인터럽트는 해당 장치가 신호를 보내는 것으로, 해당 장치에 대한 드라이버가 인터럽트를 처리하는 인터럽트 핸들러 함수를 등록합니다.
소프트웨어 인터럽트
트랩(trap)이라고도 하며, 시스템콜이나 예외상황에서 발생하며, 인터럽트 핸들러 함수를 통해 처리됩니다. 시스템콜의 경우 프로세스가 커널 모드에서 유저 모드로 스위칭할 때 사용되며, 프로세스는 커널에 해당 핸들러 함수의 호출을 요청하고, 커널은 시스템콜을 처리하기 위해 소프트웨어 인터럽트를 발생시키고 핸들러 함수를 실행합니다.
- DMA 컨트롤러 : 입출력 디바이스가 메모리에 직접 접근할 수 있도록 하는 하드웨어 장치를 뜻하며, CPU에만 너무 많은 인터럽트 요청이 들어오기 때문에 CPU 부하를 막고 CPU의 일을 대신 부담하기도 하며 하나의 작업을 CPU와 DMA 컨트롤러가 동시에 처리하는 것을 방지합니다.
- 메모리 : 전자회로에서 데이터나 상태, 명령어 등을 기록하는 장치를 말하며, 보통 RAM(Random Access Memory)를 일컬어 메모리라고도 합니다. CPU는 계산을, 메모리는 기억을 담당합니다.
- 타이머 : 특정 프로그램에 시간제한을 거는 역할을 하며, 시간이 오래 걸리는 프로그램의 제한을 걸기위해 사용합니다.
- 디바이스 컨트롤러 : 컴퓨터와 연결되어 있는 IO 디바이스의 작은 CPU를 말합니다.
메모리
3-2 메모리 계층
메모리 계층은 레지스터, 캐시, 메모리, 저장장치로 구성되어 있습니다.
- 레지스터 : CPU안에 있는 작은 메모리, 휘발성 메모리로 속도는 가장 빠르나 용량이 적고 CPU가 실행하는 명렁어는 레지스터에 저장된 데이터를 이용하여 처리하며, 결과도 레지스터에 저장되고 CPU의 동작을 제어하는데 중요한 역할을 합니다.
- 캐시 : 데이터나 명령어등에 빠르게 접근하기 위해 CPU와 메인 메모리 사이에 위치한 일종의 임시저장소로 L1, L2 캐시를 지칭하며 휘발성 메모리로 속도가 빠르나 역시 용량이 적다.
- L1 캐시 : CPU내부에 위치하며, 가장 빠른 속도로 데이터와 명령어를 저장하고 처리할 수 있다. 일반적으로 몇십KB 정도의 작은 용량으로 데이터와 명령어 각각에 대한 별도 캐시가 존재하고 CPU에서 다수의 명령어를 병렬 처리 하기 위함입니다.
- L2 캐시 : CPU내부에 위치하지만, L1캐시보다 용량은 크지만 느리고 L1 캐시에서 찾지 못한 데이터를 대체 제공하는 등의 역할을 수행하며 L2 캐시의 용량은 몇백KB ~ 메가바이트까지 다양하고 다수 코어를 가진 CPU의 경우 각 코어마다 L2 캐시가 존재합니다.
- 주기억장치 : CPU가 직접 접근하여 데이터를 읽고 쓸 수 있는 기억장치로 RAM이 포함되어 있으며, 휘발성 메모리에 속도와 용량은 보통입니다.
- 보조기억장치 : CPU가 직접 접근할 순 없고 데이터를 읽거나 쓸 때 주기억장치를 거쳐야 합니다. HDD, SDD를 일컬으며 비휘발성에 속도는 낮지만 용량이 큽니다.
캐시
Cache는 데이터를 미리 복사해 놓는 임시 저장소이자 빠른 장치와 느린 장치에서 속도 차이에 따른 병목 현상을 줄이기 위한 메모리입니다.
하지만 실제로 메모리와 CPU 사이의 속도 차이가 너무 크기 때문에 그 중간에 레지스터 계층을 통해 속도차이를 해결하며 이 계층을 캐싱 계층이라고 합니다.
이 캐싱 계층을 두는 것 말고 캐시를 직접 설정할 때는 지역성을 기반으로 설정해야 합니다. 지역성은 자주 사용하는 데이터를 기반으로 시간 지역성(temporal locality)과 공간 지역성(spatial locality)으로 나뉩니다.
- 시간 지역성 : 최근 사용한 데이터에 다시 접근하려는 특성을 말하며 for loop문의 index i같은 변수의 경우가 예로 들 수 있습니다.
- 공간 지역성 : 최근 접근한 데이터를 이루고 있는 공간이나 그 가까운 공간에 접근하는 특성을 말하며 배열에서 요소의 index i 같은 경우 입니다.
캐시히트, 캐시미스
캐시에서 원하는 데이터를 찾았다면 캐시히트, 해당 데이터가 캐시에 없다면 주 메모리에서 찾아오기 때문에 캐시미스 라고 하며 캐시히트를 하게 되면 데이터를 제어장치를 거쳐 가져오게 됩니다. 캐시히트의 경우 위치도 가깝고 CPU 내부 버스를 기반으로 작동하기 때문에 속도가 빠릅니다. 반면 캐시미스가 발생하면 메모리에서 가져오면서 시스템 버스를 기반으로 작동하기 때문에 느립니다.
캐시매핑
캐시가 히트되기 위해 매핑하는 방법을 말하며 CPU의 레지스터와 주 메모리(RAM)간에 데이터를 주고받을 때 기반으로 설명합니다.
- 직접 매핑 (directed mapping) : 메모리가 1~100 일 때 캐시가 1~10이 있다면 1:1~10, 2:1~20… 등 매핑하는 방법을 말하고 처리가 빠르지만 충돌 발생확률이 높습니다.
- 연관 매핑 (associative mapping) : 순서를 일치시키지 않고 관련 있는 캐시와 메모리를 매핑하며 충돌이 적지만 모든 블록을 탐색해야 하므로 속도가 느립니다.
- 집합 연관 매핑 (set associative mapping) : 직접 매핑과 연관 매핑을 합쳐 놓은 것으로 순서는 일치시키지만 집합을 둬서 저장하며 블록화되어 있기 때문에 검색은 좀 더 효율적입니다.
웹 브라우저의 캐시
웹 브라우저의 작은 저장소 쿠키, 로컬 스토리지, 세션 스토리지가 있으며 사용자의 정보나 인증 모듈 관련 사항들을 웹 브라우저에 저장해서 추후 서버에 요청할 때 자신을 나타내는 아이덴티티나 중복 요청 방지를 위해 사용합니다.
- 쿠키 : 만료기한이 있는 Key-Value 구조의 저장소 입니다.same site 옵션을 strict로 설정하지 않았을 경우 다른 도메인에서 요청했을 때 자동 전송되며, 4KB까지 데이터를 저장하고 만료기한을 설정할 수 있습니다. 쿠키 설정 시 document.cookie 로 쿠키를 볼 수 없게 httponly로 설정하는 것이 중요하며 만료기한등의 설정은 보통 서버에서 정합니다.
- 로컬 스토리지 : 만료기한이 없는 key-value 구조의 저장소로 10MB까지 저장 가능하며 웹 브라우저를 닫아도 유지되고 도메인 단위로 저장, 생성됩니다. HTML5를 지원하는 웹 브라우저에서만 사용할 수 있고 클라이언트에서만 수정 가능합니다.
- 세션 스토리지 : 만료기한이 없는 key-value 구조의 저장소로 탭 단위로 세션 스토리지를 생성하며 탭을 닫을 때 해당 데이터를 삭제합니다. 5MB까지 저장하며 HTML5를 지원하는 웹 브라우저에서만 사용할 수 있고 클라이언트에서만 수정 가능합니다.
데이터베이스의 캐싱 계층
참고로 데이터베이스에서도 시스템을 구축할 때 메인 데이터베이스 위에 Redis 같은 데이터베이스 계층을 ‘캐싱 게층’으로 둬서 성능을 향상시키기도 합니다.
2-2 메모리 관리
운영체제의 대표적인 역할 중 하나는 메모리 관리입니다.
가상 메모리
virtual memory는 메모리 관리 기법의 하나로 컴퓨터가 실제로 이용 가능한 메모리 자원을 추상화하여 이를 사용하는 사용자들에게 매우 큰 메모리로 보이게 만드는 기법을 뜻합니다.
이때 만들어진 주소를 가상 주소(logical address) 라고 하며 실제 메모리상에 있는 주소를 실제 주소(physical address) 라고 합니다. 가상 주소는 메모리관리장치(MMU)에 의해 실제 주소로 변환되며, 사용자는 실제 주소를 의식할 필요 없이 프로그램을 구축할 수 있게 됩니다.
가상 메모리는 가상 주소와 실제 주소가 매핑되어 있고 프로세스의 주소 정보가 들어 있는 ‘페이지 테이블’로 관리됩니다. 이때 속도 향상을 위해 TLB를 씁니다.
- TLB : 메모리와 CPU 사이에 있는 주소 변환을 위한 캐시로 페지이 테이블에 있는 리스트를 보관하며 CPU가 페이지 페이블까지 가지 않도록 해 속도를 향상시킬 수 있는 캐시 계층이다.
스와핑
실제 메모리인 RAM에는 현재 없는 데이터나 코드에 접근할 경우 페이지 폴트가 발생하며 이 때 메모리에서 당장 사용하지 않는 영역을 하드디스크로 옮기고 하드디스크의 일부불을 마치 메모리처럼 불러와 쓰는 것을 스와핑이라고 합니다.
페이지 폴트
프로세스의 주소 공간에는 존재하지만 지금 이 컴퓨터의 RAM에는 없는 데이터에 접근했을 경우에 발생합니다
- CPU는 물리 메모리를 확인하여 해당 페이지가 없으면 트랩을 발생해서 운영체제에 알립니다.
- 운영체제는 CPU의 동작을 잠시 멈춥니다.
- 운영체제는 페이지 테이블을 확인하여 가상 메모리에 페이지가 존재하는지 확인하고 없으면 프로세스를 중단하고 현재 물리 메모리에 비어 있는 프레임이 있는지 찾습니다. 물리 메모리에도 없다면 스와핑이 발동됩니다.
- 비어 있는 프레임에 해당 페이지를 로드하고, 페이지 테이블을 최신화 합니다.
- 중단되었던 CPU를 다시 시작합니다.
- 페이지 : 가상 메모리를 사용하는 최소 크기의 단위
- 프레임 : 실제 메모리를 사용하는 최소 크기의 단위
스레싱
thrashing은 메모리의 페이지 폴트율이 높은 것을 의미하며 이는 컴퓨터의 심각한 성능 저하를 초래합니다.
메모리에 너무 많은 프로세스가 동시에 올라가게 되면 스와핑이 많이 일어나서 발생하는 것으로 페이지 폴트가 일어나면 CPU 이용률이 낮아지고, 운영체제는 낮은 이용률을 보고 가용성을 높이기 위해 더 많은 프로세스를 메모리에 올리게 됩니다. 이를 해결하기 위해선 메모리를 늘리거나, HDD를 사용한다면 SDD로 교체하는 방법등이 있고 운영체제에서 이를 해결하려면 ‘작업 세트’ 와 ‘PFF’가 있습니다.
- 작업세트 : working set은 프로세스의 과거 사용 이력인 지역성(locality)을 통해 결정된 페이지 집합을 만들어서 미리 메모리에 로드하는 것 입니다. 미리 메모리를 로드하면 탐색비용을 줄이고 스와핑을 줄일 수 있습니다.
- PFF : Page Fault Frequency는 페이지 폴트 빈도를 조절하는 방법으로 상한선과 하한선을 만드는 방법입니다. 만약 상한선에 도달한다면 프레임을 늘리고, 하한선에 도달한다면 프레임을 줄입니다.
메모리 할당
메모리에 프로그램을 할당할 땐 시작 메모리 위치, 메모리의 할당 크기를 기반으로 할당하는데, 연속 할당과 불연속 할당으로 나뉩니다.
- 연속 할당 : 메모리에 ‘연속적’으로 공간을 할당하는 것입니다. 아래 처럼 순차적으로 공간에 할당할 때 메모리를 미리 나누어 관리하는 ‘고정 분할 방식’과 매 시점 프로그램에 크기에 맞게 메모리를 분할하는 ‘가변 분할 방식’이 있습니다.
- 고정 분할 방식 (fixed partition allocation) 은 메모리를 미리 나누어 관리하는 방식으로 미리 나누어 있기 때문에 융통성이 없고 내부 단편화가 발생합니다.
- 가변 분할 방식 (variable partition allocation) 은 매 시점 프로그램의 키그의 맞게 동적 분할하는 방식으로 내부 단편화는 발생하지 않지만 외부 단편화는 발생할 수 있으며, 최초적합, 최적적잡, 최악접합이 있습니다.
- 최초적합 : 위쪽이나 아래쪽부터 홀을 찾으면 바로 할당합니다.
- 최적적합 : 프로세스의 크기 이상인 공간 중 가장 작은 홀부터 할당합니다.
- 최악적합 : 프로세스의 크기와 가장 많이 차이가 나는 홀에 할당합니다.
- 내부 단편화 : 메모리를 나눈 크기보다 프로그램이 작아서 들어가지 못하는 공간이 발생하는 현상
- 외부 단편화 : 메모리를 나눈 크기보다 프로그램이 커서 들어가지 못하는 공간이 많이 발생하는 현상
- 홀 : 할당할 수 있는 비어있는 메모리 공간을 의미합니다.
불연속 할당
메모리를 연속적으로 할당하지 않는 불연속 할당은 메모리를 동일한 크기의 페이지로 나누고 프로그램마다 페이지 테이블을 두어 이를 통해 메모리에 프로그램을 할당하는 것입니다. 페이징 기법 말고도 세그멘테이션, 페이지드 세그멘테이션이 있습니다.
- 페이징 : 동일한 크기의 페이지 단위로 나누어 메모리의 서로 다른 위치에 프로세스를 할당합니다. 홀의 크기가 균일하지 않은 문제가 없어지지만 주소 변환이 복합해집니다.
- 세그멘테이션 : 페이지 단위가 아닌 의미 단위인 세그먼트로 나누는 방식으로 프로세스는 코드, 데이터 ,스택, 힙 등으로 이뤄지는데 코드와 데이터 등 이를 기반으로 나눌 수 있으며 함수 단위로 나눌 수도 있습니다.
- 페이지드 세그멘테이션 : 공유나 보안을 의미 단위의 세그먼트로 나누고 물리적 메모리는 페이지로 나누는 것을 뜻합니다.
페이지 교체 알고리즘
메모리는 한정되어 있기 때문에 스와핑이 많이 일어나며 이를 많이 일어나지 않도록 설계해야하며 페이지 교체 알고리즘을 기반으로 나누는 것을 말합니다.
- 오프라인 알고리즘 : 먼 미래에 참조되는 페이지와 현재 할당하는 페이지를 바꾸는 알고리즘이며, 가장 좋은 방법이며 사용할 수 없는 알고리즘이지만 다른 알고리즘과의 성능 비교에 대한 기준을 제공합니다.
- FIFO : First In first Out는 가장 먼저 온 페이지를 교체 영역에 가장 먼저 놓는 방법을 의미합니다.
- LRU : Least Recentle Used : 참조가 가장 오래된 페이지를 바꾸며 오래된 것을 파악하기 위해 각 페이지 마다 계수기, 스택을 두어야 한다는 점이 있습니다. LRU구현을 프로그래밍 코드로 구현할 땐 보통 두개의 자료구조 해시 테이블과 이중 연결 리스트를 사용합니다. 해시 테이블은 이중 연결 리스트에서 빠르게 찾을 수 있도록 쓰고 이중 연결 리스트는 한정된 메모리를 나타냅니다.
- NUR : LRU에서 발전한 알고리즘으로 Not Used Recently 의 약자로 일명 clock 알고리즘이라고도 하며 먼저 0과 1을 가진 비트를 두고, 1은 최근에 참조되었고 0은 참조되지 않음을 의미합니다. 시계 방향으로 돌며 0을 찾고 0을 찾게 되면 해당 프로세스를 교체하고 해당 부분을 1로 바꾸는 알고리즘입니다.
- LFU : Least Frequently Used는 가장 참조 횟수가 적은 페이지를 교체합니다.