내가 나를 돌이켜보면 무엇을 하던지 그 중심에 있는 핵심본질들을 파악해 이것으로 그 문제들을 해결하려는 성격인 것 같다.
개발자의 길을 걸어가면서도 내 이런 성격이 발동해서 이 쪽 분야의 핵심본질은 무엇일까를 고민을 많이 했다. 부트캠프에서는 배우는 것들은 프레임워크와 기술에 치우쳐진 느낌이 많았는데 나는 항상 그것보다 더 중요한 근본이 있을 것이라 생각했다. 몇 주간의 연구결과 컴퓨터공학 지식이 그 근본에 해당한다는 것을 파악했고 이것에 시간을 들여 흔들리지 않는 내 기본실력을 만들어내야 한다는 생각이 들었다.
컴퓨터 공학의 모든 과목을 다 볼 수는 시간적으로 없기에 백엔드 실무에 가장 필요한 필수과목들의 기본을 다지는 것이 우선이라 생각이 들었다.
운영체제, 자료구조와 알고리즘, 데이터베이스, 네트워크, 컴퓨터구조가 이에 해당될 것 같고, 운영체제를 먼저 공부 할 것이다.
왜 운영체제를 먼저 공부하게 되었냐고 하면
운영체제의 원리를 알게 되면 한줄 요약하자면, 버그와 각종 문제들을 만났을 때 이를 해결할 수 있는 근본이 되기 때문이다. 그리고 운영체제를 알면 성능 면에서도 좀 더 다각도로 볼 수 있다.
인프런에서 운영체제 강의를 설날 전에 찾아서 두번 정도 가볍게 돌려봤는데 처음 들어보는 것이라 첫번째 들을 때에는 어렵긴 했다.
이제 본격적으로 운영체제에서 공부한 내용들을 기록해나가려고 한다.
< 운영체제 개요 >
컴퓨터는 운영체제 없이 돌아가는가? 그렇다.
하지만, 설계한 그대로로만 돌아가고 다른 기능은 안 된다.
예시로 전화기와 스마트폰을 비교하면 이해하기 쉽다.
< 운영체제가 하는 일 >
< 운영체제의 역사 >
1940년대 - 애니악 개발. 하드웨어 비용이 비싸서 어떻게 하면 CPU를 많이 쓸 수 있을까를 고민함
1950년대 초반 - 직접회로를 개발하고 현대 모습의 컴퓨터가 탄생함.
1950년대 중후반 - '싱글스트림 배치시스템'을 개발함.
I/O 디바이스 관리자 만들어 CPU 쉬지 않게 만듬. 하지만 I/O에도 CPU를 기다려야 하는 경우도 있다.
1960년대 - '시분할 시스템' 개발(여러 작업을 가능하게 시간을 나눠서 실행되게). 파일 시스템이 등장했음.
+UNIX 운영체제의 등장(멀티프로그래밍,다중사용자,파일시스템 제공) => 이 때 메모리 침범 이슈가 생김.
1970년대 - 개인컴퓨터(애플의 매킨토시,마소의 MS-DOS) 출시
< 운영체제의 핵심 >
< 컴퓨터 >
< CPU의 구조 >
중앙처리장치라는 뜻이며,
세가지로 이루어져있다.
< 메모리 종류 >
RAM(메인 메모리로 사용)
ROM(데이터를 한번 쓰면 수정불가하기 때문에 부팅과 관련된 BIOS를 저장함)
< 컴퓨터 부팅과정 >
< 인터럽트 >
=> 인터럽트 방식을 만듬.
'인터럽트'는 CPU가 입출력 관리자에게 입출력 명령 내리고,다른 작업을 한다. 입출력 관리자가 입출력 완료되었을 때 CPU에 신호를 주고 인터럽트 서비스루틴(ISR) 실행시켜 작업을 완료함.
< 프로그램/프로세스 >
프로그램이란? 하드디스므 등에 저장된 명령문의 집합체(어플리케이션이라고도 부름)
프로세스란? 실행 중인 프로그램을 말함.
하드디스크에 있던 프로그램이 메모리에 올라간 것.
프로그램은 하드디스크만 이용하는 수동적인 존재.
프로세스는 메모리도 쓰고, CPU도 쓰고 필요에 따라 입/출력도 하기 때문에 능동적인 존재.
< 프로세스의 구조 >
-코드영역: 자신을 실행하는 코드가 저장됨.
-데이터영역: 전역변수와 static(정적)변수가 저장되어 있음.
-스택영역: 지역변수와 함수 호출 시에 필요한 정보들이 저장됨.
-힙 영역: 프로그래머가 동적으로 메모리를 할당하는 데에 쓰인다.
< 컴파일 과정 >
.c -> 전처리기 -> .i -> 컴파일러 -> 어셈블리어로 변경(.s) -> 어셈블러 -> 기계어로 변경(.o) -> 링커 -> 링킹
< 멀티프로그래밍/멀티프로세싱 >
-유니프로그래밍: 메모리에 하나의 프로세스가 올라간 것을 말함.
멀티프로그래밍: 메모리에 여러개의 프로세스가 올라간 것.(
메모리의 관점)
멀티프로세싱: (CPU관점) CPU가 여러개의 프로세스를 처리하는 것.
< PCB >
-운영체제는 프로세스들을 전부 관리하고, 공평하게 실행시켜야 함.
프로세스가 실행되면 해당 프로세스의 정보를 가진 PCB를 만들고 저장.
-PCB는 연결리스트라는 자료구조로 저장됨.(PCBa-PCBb-PCBc)
-운영체제는 프로세스가 종료되면 해당 PCB를 제거, 남은 PCB는 연결리스트구조 유지
< PCB의 구조 >
-포인터: 부모와 자식프로세스에 대한 포인터. 할당된 자원에 대한 포인터 등... 효율적인 접근을 위해 포인터 사용.
-프로세스 상태: 현재 프로세스의 5가지 상태를 나타냄
(생성-준비-실행-대기-완료)
-프로세스 ID: 프로세스를 식별하기 위한 숫자.
-프로그램 카운터:다음에 실행될 명령어의 주소를 포함하는 프로그램 카운터를 저장. '시분할 시스템' 다시 시작할 때에 프로그램 카운터가 꼭 필요함.
-레지스터 정보: 프로세스가 실행될 때 사용했던 레지스터 값들이 저장됨(프로그램 카운터와 비슷한 용도)
-메모리 관련 정보
-CPU스케줄링 정보
-etc...
< 프로세스 상태 >
-생성:PCB를 생성하고 메모리에 프로그램 적재를 요청한 상태
-준비:승인을 받으면, CPU를 사용하기 위해 기다리고 있는 상태
-실행:준비상태 프로세스가 CPU스케줄러에 의해 CPU할당받아 실행되는상태-> 실행상태의 프로세스의 수는 CPU의 갯수 만큼.
-대기:프로세스가 입출력을 하면 입출력이 완료될 때까지 기다리는 상태
CPU는 굉장히 빠른데,입출력은 상대적으로 느림.'입출력 요청을 한 프로세스'
-완료:프로세스가 종료된 상태.프로세스가 사용했던 데이터를 메모리에서 제거하고, 생성된 PCB도 제거함.
< 컨텍스트 스위칭 >
< 프로세스 생성과 종료 >
위의 과정은 부팅되소 0번 프로세스 만들 때에만 실행됨.
다른 프로세스들은 0번 프로세스 복사해서 사용한다(더 빠름)- 자식/부모 프로세스가 생김.
-exec() 함수로 원하는 값을 덮어씌움.
자식 프로세스가 종료되고 신호를 줘서 부모프로세스가 종료되는 것이 선순서인데, 꼬여서 메모리에 계속 살아있는 상태를 '좀비프로세스'라 한다.
-> 컴퓨터 껐다켜서 초기화시켜야 함.
< 쓰레드 >
프로세스 수가 늘어나면 PCB가 늘어가 무거워짐(메모리를 너무 많이 차지함)
=> 그래서 고안된 것이 '쓰레드!"
: 프로세스 내에 1개 이상이 있을 수 있고 여러개가 가능하다.
이 쓰레드는 PCB 내의 코드,데이터,힙영역을 공유하는데 스택영역은 공유하지 않는다.쓰레드마다 각각 하나씩 보유한다.-> 메모리 절약이 많이 됨.
이제 운영체제가 관리하는 단위는 프로세스 내의 쓰레드가 됨.
< 프로세스와 쓰레드의 비교 >
-쓰레드는 공유공간 내에서 문제가 생길수 있는데 이는 나중에 '프로세스 동기화'쪽에서 알아본다.