CS >
sync/async & blocking/non-blocking 2 [0] 2025-01-20 |
sync/async & blocking/non-blocking [0] 2025-01-12 |
CPU Bound - I/O Bound [0] 2025-01-10 |
동시성과 실행 유닛 [0] 2025-01-02 |
프로세스 [0] 2025-01-01 |
sync/async & blocking/non-blocking 2 [0] 2025-01-20 |
sync/async & blocking/non-blocking [0] 2025-01-12 |
CPU Bound - I/O Bound [0] 2025-01-10 |
동시성과 실행 유닛 [0] 2025-01-02 |
프로세스 [0] 2025-01-01 |
그럴 때마다 먼저 경험한 재야의 고수들이 만들어놓은 라이브러리와 같은 구현체의 도움을 받아 쉽게 해결하곤 합니다.
그치만 점점 이 일을 할수록 어떤 원리로 동작하는 지 제대로 모르고 덤볐다가 시간은 시간대로 들고, 제대로 해결도 안되는 경험을 하게 됩니다.
(특히 최적화 같은...)
내부를 파고 들다보면 전공에서 배운 개념들을 만나게 되고, 반갑기도 하고 다시 볼 일 없을 것 같은 녀석을 만나면 놀라기도 합니다. 😂
왜 모든 분야에서 기본기를 강조하는 지 이해가 됩니다. ㅎㅎ
그래서 틈틈이 중요하다고 생각하는 개념들을 복습하면서 공유해보고자 합니다!
프로그램이 이제 메모리에 올라갔습니다. 프로세스는 메모리에서 크게 Text, Data, Heap, Stack 네가지 섹션으로 구분됩니다.
(UNIX 시스템 기준으로 상위 1GB는 커널이, 하위 3GB는 사용자 애플리케이션이 차지합니다.)
text(=code) | 컴파일된 기계어 binary 소스 코드
data | 전역 변수(global variables)와 정적 변수(static variables), 프로세스를 실행할 때 할당되고 종료할 때 소멸.
data영역을 BSS와 GVAR(data) 영역으로 나누기도 합니다.
-> BSS: 초기화되지 않은 변수로, runtime에 0으로 초기화시킨다.
-> GVAR(data): 초기화된 변수
why ?
1. 저장 공간 효율
- 초기화된 변수와 그렇지 않은 변수를 구분하고 초기화되지 않은 변수를 runtime에 0으로 초기화하는 방법을 택함으로써, 굳이 0으로 초기화 될 데이터에 대해 초기화 데이터를 미리 저장할 필요가 없어 저장 공간을 아끼는 이점이 있습니다. (실행 파일이 작아짐)
2. 로딩 효율
- 반대로 GVAR 영역에 해당하는 변수는 실행 파일에도 포함되며 메모리로 로드될 때, 초기화된 값을 복사해 옵니다.
- BSS는 단순히 0으로 초기화하면 되기 때문에 로드 속도와 메모리 할당이 빠르고, GVAR은 실행 파일을 읽어서 메모리에 복사하는 과정에서 시간이 소요됩니다.
stack | 임시 데이터(지역 변수, 매개 변수, 리턴 값)가 저장되는 영역입니다. 메모리의 높은 주소에서 낮은 주소 방향으로 할당이 되며, 함수 호출과 리턴 시에 push & pop의 형태로 할당/소멸됩니다.
heap | 런타임에 동적으로 할당되는 영역입니다. malloc, new 같은 연산자로 필요에 따라 할당하고 free, delete 또는 gc에 의해서 해제되는(해야하는!) 데이터들이 여기에 해당합니다.
그림에서 알 수 있듯이 stack과 heap은 같은 영역을 공유합니다. stack은 위에서 아래 방향으로 heap은 아래에서 위 방향으로 공간을 차지합니다. stack 영역은 os에 따라 고정된 메모리 크기를 갖습니다.
무한 재귀 또는 정해진 stack 사이즈보다 큰 지역 변수를 선언하는 경우에 stack overflow 에러가 발생하고, 동적으로 메모리를 계속 할당하여 stack 영역을 침범하거나 이미 해제된 메모리를 포인터로 접근하는 경우에 heap overflow가 발생합니다.
따라서 대용량 데이터를 처리하거나 장시간 돌아가는 애플리케이션을 개발한다면 반드시 메모리 관리를 신경써야 합니다!
프로세스는 메모리에서 프로세스마다 고유의 공간을 가집니다. 같은 프로그램을 실행하여 두개의 프로세스가 생겼다고 할지라도 이 둘은 별개의 프로세스입니다.
예를 들면, chrome은 멀티프로세스 구조를 가진 애플리케이션입니다.
- browser: UI와 I/O 담당
- renderer: 웹 페이지 렌더링
- plug-in: 플러그인 실행
각각의 역할을 가지며 경우에 따라 자식 프로세스를 만듭니다. 우리가 보는 브라우저 탭이 그 것인데,탭을 추가하면 child process(renderer)가 spawn 됩니다.
이렇게 생성된 프로세스 역시 고유 id를 가진 개별적인 프로세스이며 이 구조 덕분에 하나의 탭에서 오류가 발생해도 브라우저 전체가 다운되지 않게 됩니다.
( single point failure를 피하고 robust한 애플리케이션 설계에 고려해볼 수 있는 구조가 되겠네요! )
OS는 PCB(process control block, also known as task control block)라는 자료 구조에 각각의 프로세스정보를 담아 관리합니다.
PCB에는 아래 그림과 같은 정보들을 포함합니다.
Program Counter와 CPU Registers는 프로세스가 제대로 동작하기 위해 interrupt이 발생할 때 반드시 저장되어야 하는 값입니다.
그 외에 Process State와 CPU 스케줄링 정보, 메모리 관리 정보, I/O 상태 정보 등이 포함됩니다.
PCB의 Process State는 현재 프로세스의 상태를 나타냅니다.
하나의 프로세서(코어)에서는 하나의 프로세스가 실행됩니다. 따라서 싱글 프로세서 환경에서는 한 프로세스만 running이고 대부분은 ready 또는 waiting 상태로 기다립니다.
지금까지 프로세스에 대해서 간략히 정리해보았습니다. 교과서에서는 Process와 Job이라는 말을 혼용해서 사용합니다. 경우에 따라 뉘앙스가 좀 다르긴 하지만 같은 의미로 봐도 무관할 것 같습니다.
초기의 컴퓨터는 하나의 일꾼(Processor)이 한번에 하나의 일(Job)을 할 수 있었을 것입니다. 그러면 지금 우리가 노래도 듣고 게임도 하고 인터넷 검색도 동시에 하는 것은 어떻게 가능하게 되었을까요? 이를 차차 알아보도록 하겠습니다.
GUEST님 환영합니다! ^_^
댓글의 비밀번호를 입력해주세요.
삭제 후에는 복구할 수 없습니다.
댓글의 비밀번호를 입력해주세요.
삭제 후에는 복구할 수 없습니다.