OS (2)
Context Switching
- CPU가 하나의 프로세스를 실행하다가 인터럽트 요청에 의해서 다음 우선순의 프로세스가 실행되어야할 때
- 기존의 프로세스 정보를 PCB에 저장하고 교체할 프로세스의 정보 상태로 교체하는 행위이다. (주체는 OS 스케쥴러)
- Context Switching하는 동안엔 CPU가 프로세스를 실행시키는 일을 하지 않고 있는 시간이 생긴다. 이를 오버헤드라고 하고 오버헤드가 많아지면 성능을 저해한다.
- https://jeong-pro.tistory.com/93
프로세스 VS 스레드
- 프로세스
- 프로세스는 프로그램의 실행되는 하나의 단위
- 각 프로세스마다 고유의 할당된 독립된 자원을 가진다. (cpu점유, 메모리…)
- 프로세스가 다중으로 실행되고 있을 때 (크롬, 멜론, 카톡…) 각 프로세스를 실행시키고 멈추고 다른 프로세스를 실행시키고 멈추고를 엄청 빠르게 계속 해야 모든 프로그램(프로세스)가 동시에 실행되는 것처럼 보인다. → 컨텍스트 스위칭
- 스레드
- 하나의 프로세스엔 여러개의 실행흐름인 스레드가 존재한다.
- 각 스레드는 하나의 프로세스 내부의 자원을 공유한다. 하지만 각 스레드는 고유의 스택 메모리를 가지고 있다.
- 멀티 스레드 프로그래밍을 할 때, 각 스레드마다 공유된 자원에 대한 동기화를 잘 시켜줘야한다.
- 동기화는 주로 뮤텍스를 사용하여 락을 걸고 릴리즈하는 방식으로 하는데 이 때 데드락이 걸리지 않게 주의해야 한다.
- 프로세스와 마찬가지로 스레드도 모든 스레드가 동시에 실행되고 있는 것처럼 컨텍스트 스위칭을 하는데 스위칭할 때마다 저장하는 것이 스택 메모리밖에 없고 나머지는 공유하기 때문에 프로세스보다 컨텍스트 스위칭 비용이 적게 든다.
컴파일 언어 VS 인터프리터 언어
- 컴파일 언어
- 프로그래밍 언어를 기계어로 컴파일하고(빌드) 컴파일된 기계어를 런타임에서 실행(java는 jvm에서)하는 방식의 언어이다.
- 이미 다 기계어가 되어있는 상태에서 실행하기 때문에 런타임에서 굉장히 빠르다.
- 인터프리터 언어
- 컴파일의 과정없이 프로그래밍 언어 한줄 한줄을 그 때마다 읽어 해석하여 명령어로 실행시킨다.
- 실행속도는 당연히 컴파일 언어보다 느리다.
- 대규모 어플리케이션에선?
- 컴파일 언어가 유리하다고 생각한다.
- 컴파일 시간은 분명 매우 길어지겠지만, 실행속도는 인터프리터 언어보다 월등하게 빠를 것이기 때문이다.
멀티 스레드 & Block I/O
- 보통의 스레드 작업엔 I/O작업이나 computed 작업이 있다.
- computed 작업은 주로 cpu나 cpu cache를 이용하거나 메인 메모리를 사용하는 작업이다.
- I/O 작업이란 말그대로 input, ouput이 있는 작업으로 외부장치와의 소통이다. 디스크 읽기, 쓰기나 외부 api call할 때 네트워크 요청, 응답과 같은 작업이다.
- 멀티 스레드 방식으로 I/O 작업을 하는 건 좋지 못하다.
- 일반적인 어플리케이션은 아래 이미지와 같이 Blocking I/O 방식을 사용한다.
- 만약 서버 어플리케이션을 구현하여 대규모 요청을 받아서 처리해야하는 상황이라면 멀티 스레드 방식이 필수가 됐었다. 그런데 멀티 스레드 방식으로 구현해도 이런 Blocking I/O 작업은 불리한 점이 존재한다.
- 멀티스레딩이 동시에 여러 스레드들을 돌리는거지만 실상은 동시에 돌리는 것처럼 보이는거고 사실은 아주 짧은 주기로 스레드들이 실행되었다가 멈추는 과정의 반복이다. 여러 스레드들이 CPU를 점유하기 위해 context switching을 하는데 그 과정에서 어쩔 수 없이 놀고 있는 스레드가 발생할 수 밖에 없다.
- Blocking I/O 작업 자체의 문제인데 Blocked 상태에선 어쩔 수 없이 응답이 올 때까지 기다릴 수 밖에 없다는 것이다.
- 사용자의 요청 수만큼 스레드가 생성되고 삭제될텐데 시스템의 자원은 한정되어있으므로 대규모 트래픽엔 뻑이 날 수 밖에 없다.
GC
- 프로그램이 제대로 동작하려면 메모리에 값을 할당하고 해제하는 과정이 필요하다.
- 이를 자동으로 관리해주는 것이 garbage collector이다.
- memory leaks : 메모리를 사용하고 나서 해제하지 않아서 메모리 누수가 발생할 수 있는데 이를 예방해준다.
- dangling pointer : 삭제된 객체의 포인터가 재사용되는 현상을 예방할 수 있다.
- gc를 쓸 때 주의해야할 점 또한 존재한다.
- performance impact : gc 또한 컴퓨팅 자원을 사용하기 때문에 많이 일어날수록 성능에 영향을 줄 수 있다.
- unpredictable stalls : gc가 수행하고 있으면 application은 잠시 멈춘다. (stop the world - STW시간)
- 메모리 종류
- stack : 지역 변수나 객체의 참조 포인터를 저장
- heap : 문자열이나 참조형 객체를 저장
- https://yceffort.kr/2020/12/javascript-garbage-collection
- https://velog.io/@kineo2k/Go-언어의-GC
댓글남기기