Skip to content

Latest commit

 

History

History
152 lines (109 loc) · 16.5 KB

Operating System.md

File metadata and controls

152 lines (109 loc) · 16.5 KB

Operating System

📖 Contents


운영체제란

  • 운영체제(Operating System)란, 컴퓨터 하드웨어 바로 윗단에 설치되는 소프트웨어를 의미한다. 그래서 사용자 및 다른 모든 소프트웨어와 하드웨어를 연결해주는 역할을 한다.

  • 따라서, 전원을 켰을 때 운영체제가 없으면 그 컴퓨터는 고철 덩어리에 불과하며, 이 고철을 동작시키기 위해서 필요한 기본적인 소프트웨어가 바로 운영체제이다.

    • 사용자 입장에서는 하드웨어 자체를 다루기 쉽지 않으므로, 하드웨어 위에 기본적으로 운영체제를 탑재해서 전원을 켰을 때 손쉽게 사용할 수 있는 상태가 되도록 하는 것이다.
  • 각종 소프트웨어들은 하드웨어와 운영체제가 한 몸으로 존재하는 "컴퓨터 시스템" 위에서 수행되는 것으로 볼 수 있다.


커널

  • 컴퓨터의 전원을 켜면 운영체제도 같이 실행이 된다. 그리고 기본적으로 모든 소프트웨어가 컴퓨터 시스템에서 실행되기 위해서는 메모리에 그 프로그램이 올라가 있어야 한다.

  • 운영체제 자체도 하나의 소프트웨어로서 전원 켜짐과 동시에 메모리에 올라간다. 하지만 운영체제는 규모가 너무 크기 때문에 운영체제 중, 항상 필요한 부분만을 전원이 켜짐과 동시에 메모리에 올려놓고 그렇지 않은 부분은 필요할 때 메모리로 올려서 사용하게 된다.

    • 이 때, 메모리에 상주하는 운영체제의 부분을 커널(Kernel)이라고 부른다. 이 커널을 좁은 의미의 운영체제라고도 한다. 즉, 커널은 운영체제 코드 중에서도 핵심적인 부분을 뜻한다.
  • 관련 블로그


프로세스와 스레드

  • 과거의 컴퓨터는 게임을 다운로드 하는 작업, 마우스나 키보드로부터 입력을 받는 작업, 브라우져로 사이트를 돌아다니는 작업 등 작업을 동시에 하지 못하고 한 번에 하나씩만 할 수 있었다.
  • 컴퓨터가 프로세스 여러 개를 함께 돌리는 멀티태스킹이 가능해지기 전까지는 이런 현상이 일어났다고 한다.

프로세스

  • 컴퓨터에서 실행할 수 있는 파일, 윈도우의 경우 이름 뒤쪽에 .exe가 붙어있는 그런 파일들을 "프로그램" 이라고 한다. 이러한 프로그램이 메모리에 올라가서 프로세스가 되고 CPU를 얻고 빼앗기는 과정을 반복하여 프로그램이 진행된다.
    • 즉, 프로세스는 운영체제의 지배를 받으며 수행된다고 볼 수 있다.
  • 프로그램이 실행되서 돌아가고 있는 상태, 즉 컴퓨터가 어떤 일을 하고 있는 상태 / 컴퓨터에서 연속적으로 실행되고 있는 컴퓨터 프로그램을 "프로세스" 라고 한다. 또한, 운영체제로부터 프로세서, 필요한 주소 공간, 메모리 등 자원을 할당받는 작업의 단위라고도 볼 수 있다.
  • 오늘날 우리들이 컴퓨터를 쾌적하게 사용할 수 있는 건, 운영체제가 여러 개의 프로세스를 함께 돌리고 있기 때문이다.
    • ex) 윈도우의 경우 작업관리자로 들어가서 컴퓨터에 얼마나 많은 프로세스들이 지금도 돌고 있는지 확인할 수 있음.

동시성

  • 프로세서(CPU) 하나가 이거 조금 하고 이거 조금 하고 이런식으로 여러 작업을 돌아가면서 일부분씩 진행하는 것.
    • 이렇게 진행중인 작업을 바꾸는 것을 "Context Switching" 이라고 하는데 여기에는 다양한 방식과 알고리즘이 사용된다.
      이 과정이 빨리 돌아가기 때문에 사람들에게는 이 프로세스가 마치 동시에 진행되는 것처럼 느껴지게 된다.

병렬성

  • 프로세서 하나에(하나안에) 코어 여러개가 달려서 코어 각각이 동시에 작업들을 수행하는 것.
    ex) 듀얼코어, 쿼드코어, 옥타코어 등 이런 명칭이 붙는 멀티코어 프로세서가 장착된 컴퓨터에서만 할 수 있는 방식.
  • CPU의 속도가 발열 등 물리적 제약 때문에 예전만큼 빠르게 발전하지 못하자, 그 대안으로 코어를 여러 개 달아서 작업을 분담할 수 있도록 만든 것이다.

스레드

  • 컴퓨터는 현재 여러 프로세스를 함께 돌릴 수 있게 되었지만, 이걸로 충분할까?

  • 브라우저도 하나의 프로그램이고 이게 돌면서 하나의 프로세스가 진행되고 있다.
    그런데 브라우저가 일을 할 때도, 브라우저 안에서도 게임을 다운받는 동시에 다른 페이지들을 돌아다닐 수 있어야 하고 유튜브 영상의 데이터를 받아오면서 받아진 데이터로 영상을 실행할 수도 있어야 한다.
    -> 한 프로세스 내에서도 여러 갈래의 작업들이 동시에 진행될 필요가 있는 것이다.
    -> 즉, 프로세스 내에서 실행되는 여러 흐름의 단위를 "스레드" 라고 부른다.

  • 멀티 프로세스로 할 수 있는 작업들을 굳이 하나의 프로세스에서 스레드로 나눠서 일을 하는 이유는, 운영체제는 시스템 자원을 효율적으로 관리하기 위해서 스레드를 사용하기 때문이다. 또한, 프로세스 간의 통신보다 스레드 간의 통신 비용이 적어 작업들 간의 통신 부담이 줄어들게 된다.

ex) 프로세서는 요리사라고 가정한다면, 대량주문이 들어오는 식당에서 끊임없이 만들어내는 요리 메뉴 하나하나가 바로 프로세스라고 할 수 있다.
컴퓨터는 프로세스마다 자원을 분할해서 할당하게 된다.
라면 끓이는 섹션, 김밥 마는 섹션, 햄버거 만드는 섹션 등 이렇게 조리 공간을 나눠서 요리사 혼자 돌아다니면서 동시적으로 하든 여럿이서 병렬적으로 하든 혹은 이 2가지 방법을 섞어서 하든 이 메뉴들을 계속해서 만들어 나가는 것이다.
햄버거를 만드는 프로세스에서는 패티를 굽는 스레드가 진행되는 동안, 빵에 야채를 얹고 소스를 뿌리는 스레드도 진행될 수 있을 것이다.
-> 이처럼 한 메뉴의 스레드들은 같은 조리대에서 진행된다. 같은 메뉴를 만들때는 같은 공간과 장비, 즉 같은 자원을 공유하는 것이 더 효율적이기 때문이다. 프로세스들은 컴퓨터의 자원을 분할해서 쓰지만, 스레드는 프로세스마다 주어진 전체 자원을 함께 사용하는 것이다.

이러한 방법이 속도와 효율면에서는 좋겠지만, 단점도 존재한다.
프로세스 안에서 공유되는 변수에 스레드 2개가 동시에 손을 댄다면, 컴퓨터에서는 에러가 나게 된다.
이렇게 시간 문제로 발생하는 이런 상황들을 예상하고 방지해야 하기 때문에 스레드를 사용하는 프로그래밍은 코드를 짜기도, 디버깅을 해서 오류를 찾아내고 원인을 밝히기도 굉장히 까다로운 경우가 많다.

  • 다행히도 이런 작업들을 더 쉽고 안전하게 할 수 있는 도구들이나 프로그래밍 방식들이 오늘날의 개발자들을 많이 도와주고 있다.

non-blocking call이란

  • non-blocking 방식은 I/O작업을 진행하는 동안 유저 프로세스의 작업을 중단시키지 않고, 유저 프로세스가 I/O를 처리하기 위해 커널에 함수를 호출하는 system call이 진행되면 커널에서 함수의 진행 상황과 상관없이 바로 결과를 반환하는 것을 의미한다.

  • 즉, 애플리케이션 실행 시 운영체제 대기 큐에 들어가지 않고 실행 여부와 관계없이 바로 응답을 보내는 경우를 의미한다.

    • 다른말로 하면 호출된 함수가 바로 리턴해서 호출한 함수에게 제어권을 넘겨주고, 호출한 함수가 다른 일을 할 수 있는 기회를 줄 수 있다면 non-blocking 방식이다.
  • I/O란, 입력(Input)/출력(Output)의 약자로 컴퓨터 및 주변장치에 데이터를 전송하는 프로그램, 운영 혹은 장치를 일컫는 말이다. 키보드와 마우스처럼 입력을 위한 기기, 프린터처럼 출력에만 사용되는 기기 등 다양하다.

  • 관련 자료


컴퓨터 구조

  • 컴퓨터에서 특정 프로그램을 실행하면, 보조기억장치(하드디스크)에 저장된 데이터를 주기억장치(메모리)로 불러와 CPU가 해당 데이터를 처리하는 과정으로 실행

  • CPU는 요리사, 디스크는 냉장고, 메모리는 도마라고 비유해볼 수 있다.

    • CPU
    • 캐시 메모리
    • 주기억장치(메모리)
    • 보조기억장치(디스크)
  • CPU : 컴퓨터와 관련된 모든 명령어들과 작업들을 수행하는 역할. 메모리로부터 데이터를 가져오고(Fetch) 명령어를 레지스터라는 곳에 저장한다. 그리고 디코딩(Decoding) 과정을 거쳐 명령어를 작동을 위한 신호로 변환한다. 마지막으로 실행(Execute)단계를 거친다.

  • 캐시 메모리 : CPU와 주기억장치 사이의 속도 차이를 완화시키기 위한 고속 버퍼(임시) 메모리로, 주기억장치와 CPU사이에 위치하며, 자주 사용하는 프로그램과 데이터를 기억한다. 이러한 캐시메모리를 사용하면 주기억장치를 접근하는 횟수가 줄어들어 컴퓨터의 처리속도가 향상된다.

  • 주기억장치 - 메모리 : 컴퓨터 내부에서 현재 CPU가 처리하고 있는 내용을 저장하고 있는 기억장치이다. 대표적으로 ROM과 RAM으로 구분된다.

    • ROM : ROM은 전원이 꺼져도 데이터들이 사라지지 않는 비휘발성 메모리이다. 오직 기억된 데이터들을 읽기만 가능하다.
    • RAM : RAM은 ROM과 달리 읽고 쓰기가 가능한 기억장치이다. 하지만 전원이 끊어지면 데이터가 전부 지워지는 휘발성 메모리이다.
  • 보조기억장치 - 디스크 : 물리적인 디스크가 연결되어있는 기억장치로, 주기억장치 보다는 느리지만 컴퓨터 전원을 끄더라도 저장된 데이터가 사라지지 않고 영구적으로 보관할 수 있는 장치이다. 대표적으로 HDD와 SSD가 있다.

    • HDD : 물리적인 디스크를 고속으로 회전시켜 데이터를 저장하는 장치이다. 디스크를 물리적으로 저장하기 때문에 충격에 약하고 소음이 발생한다. 최근에는 많이 사용되지 않고 있다.
    • SSD : SSD는 반도체 기반의 정보를 저장하는 장치이다. 물리적으로 데이터를 저장하지 않고 전기적으로 데이터를 저장하기 때문에 HDD에 비해서 속도가 빠르고 소음이 발생하지 않는다.
    • SSD가 HDD보다 빠른 이유
      • HDD는 데이터를 읽거나 쓸 때 스핀들 모터로 원판을 돌리고 헤드가 그 위를 헤집어야 하는 물리적 작동이 필요하지만, SSD는 그러한 과정이 생략되어 움직이는 부품이 없어 속도가 빠르고 전력 소모량이 적고 내구성과 신뢰성도 높다. HDD는 하드디스크드라이브(Hard Disk Drive), SSD는 솔리드스테이트드라이브(Solid State Drive)를 의미한다.
  • 관련 블로그

  • 관련 블로그 2


메모리의 구조

  • 프로그램이 실행되기 위해서는 먼저 프로그램이 메모리에 올라가야 한다.(load). 그리고 OS가 프로세스에 제공하는 메모리 공간은 아래와 같이 크게 4가지 영역으로 나뉜다.

image

4가지 영역

  • Text(code) 영역 : 메모리의 텍스트(또는 코드) 영역은 실행할 프로그램의 코드가 저장되는 영역이다. 그래서 CPU에서 코드 영역에 저장된 명령어를 하나씩 가져가서 처리한다. 읽기 전용이므로 프로그램(프로세스)은 코드 영역을 침범해 쓰기를 시도할 수 없다.

  • Data 영역 : 메모리의 데이터 영역은 프로그램의 전역(global) 변수와 정적(static) 변수가 저장 및 할당되는 영역이다. 데이터 영역은 프로그램의 시작과 함께 할당되며 프로그램이 종료되면 소멸한다.

    • 전역변수는 프로그램의 모든 영역에서 접근이 가능하고, 프로그램이 종료되지 않는 한 메모리가 소멸되지 않는다.
    • 정적변수는 전역 변수처럼 프로그램이 종료되지 않는 한 메모리가 소멸되지 않고, 특별히 초깃값을 지정하지 않아도 자동으로 0을 가진다.
    • 둘의 차이점은, 정적변수는 전역변수와 달리 프로그램이 시작되면 초기화는 딱 한 번만 수행된다. 참고 블로그
  • Heap 영역 : 프로그래머가 필요할 때마다 사용하는 메모리 영역이다. 다른 영역과는 다르게 Heap은 런타임에 결정된다. 즉, Heap 영역은 사용자에 의해 메모리 공간이 동적으로 할당되고 해제된다. 단, 사용하고 난 다음에는 반드시 해제를 해줘야 하며 그렇지 않으면 memory leak가 발생할 수 있다. C에서는 malloc.()/new 연산자를 통해 할당하고, free()/delete 연산자를 통해 동적 메모리를 해제할 수 있다.

    • Stack 영역보다 할당할 수 있는 메모리 공간이 많다는 것이 장점이지만 포인터로 메모리 영역을 접근해야 하기 때문에 다른 자료구조에 비해 데이터를 읽고 쓰는 게 느리다.
  • Stack 영역 : 메모리의 Stack 영역은 함수 안에서 선언된 지역변수, 매개변수(인자), 리턴값, 호출한 함수의 반환 주소(함수 실행이 끝난 후 돌아갈 주소), ESP(Extended Stack Pointer, 즉 현재 스택의 최상단 데이터를 가리키는 포인터) 등이 저장되고 함수 호출 시 기록되고 함수가 종료되면 제거한다. 이렇게 스택에 저장되는 함수의 호출 정보를 stack frame이라고 한다. 기록하고 종료하는 매커니즘은 LIFO인 후입선출의 구조로 이루어진다.

    • 컴파일 타임에 크기가 결정되기 때문에 무한히 할당할 수 없다. 재귀 함수가 너무 깊게 호출되거나 함수가 지역변수를 너무 많이 가지고 있어 stack 영역을 초과하면 stack overflow 에러가 발생한다.
    • 재귀함수의 경우, 실행된 함수가 종료되면 Stack 프레임에서 해당 함수에 대한 데이터가 소멸된다. 그래서 마지막에는 모든 함수가 종료되어 Stack 프레임이 비어있게 되고 프로그램이 종료된다.
  • 관련 블로그


재귀함수로 스택 메모리 이상으로 쌓이는 경우

  • 메모리 중에서도 Stack 영역에 함수와 관련된 데이터들이 쌓이게 되는데, 만약 재귀함수의 종료 조건이 제대로 설정되지 못해서 재귀가 무한히 호출되는 경우가 발생한다면 Stack의 크기는 한정되어 있으므로 결국 어느 순간에는 더 이상 스택 프레임이 쌓이지 못하고 뻗어버리는 경우가 생긴다.

  • 즉, 재귀 함수가 너무 깊게 호출되거나 함수가 지역변수를 너무 많이 가지고 있어 stack 영역을 초과하면 stack overflow 에러가 발생하게 된다.

    • Heap 영역이 초과되면 heap overflow라고 한다.
  • 재귀함수의 RecursionError

    • 재귀함수가 Python이 정한 최대 재귀 깊이보다 재귀의 깊이가 더 깊어질 때 발생하는 에러이다.
    • sys.setrecursionlimit()을 사용해서 Python이 정한 최대 재귀 갚이를 변경할 수 있다. 관련 블로그
    • 다만, 최대 재귀 깊이를 변경해서도 넘게되면 앞서 언급된 stack overflow 에러가 발생하게 된다.