이번 글의 구조는 MDN의 “웹페이지를 표시한다는 것: 브라우저는 어떻게 동작하는가”와 chrome for developers의 “최신 웹브라우저 들여다보기”시리즈를 기반으로 작성되었습니다.

사진1: CPU

사진2: GPU

사진3: Process와 Thread
Process와 Thread가 일하는 방법:
사진4: OS가 메모리에 process를 할당
사진5: 다른 process와 IPC를 통해서 통신
이 질문에 대한 궁금증을 풀기 위해 Inpa Dev의 “스레드를 많이 쓸수록 항상 성능이 좋아질까?”를 기반하여 작성했습니다. 해당 글에는 어떤 상황에 무엇이 부합한 지를 설명하고 있으니 궁금하면 직접 읽어보면 좋습니다.
(TLDR) 항상 좋지는 않다. 멀티 쓰레드는 공유하는 자원에 접근을 해야 하는데 그 작업 간의 병목이 일어나 싱글 쓰레드보다 성능이 떨어질 수 있다.
멀티 쓰레드는 공유 자원에 접근해야 하는데 데이터의 일관성과 정확성을 위해서 동기화 기법을 사용한다.
동기화 기법에는 뮤텍스(Mutex)나 세마포어(Semaphore)같은 기법이 있는데 이들은 한 번에 하나의 쓰레드만 공유 자원에 접근 가능하게 제한하여 일관성을 유지한다. 여기서 병목이 생기게되면 속도는 저하된다.
또한, CPU간의 데이터 일관성을 유지하기 위해 CPU간의 통신을 주기적으로 해줘야 하는데 이 글을 읽다보면 IPC 통신의 값이 비싼 것을 알 수 있다. 다수의 CPU간에 동기화는 결국 통신 비용의 증가를 발생한다

사진6: 메모리간의 데이터 일관성
CPU 내부의 프로세스 또는 쓰레드는 서로 동기화를 하기 위해 중간에 저장하고 다른 곳으로 전환될 때 컨택스트 스위칭 오버헤드(context switching overhead) 비용이 발생한다. 중간에 잠깐 텀이 있기에 시간과 자원을 소모한다.

사진7: 컨텍스트 스위칭 오버헤드의 예시
위 정보를 전부 총합해보면 컴퓨터의 멀티 태스킹은 우리가 생각하는 방향으로 진행되지는 않는다.
![]()
사진8: 사람이 생각하는 멀티태스킹과 컴퓨터가 하는 멀티태스킹
따라서, 만들고자 하는 서비스의 성격에 따라서 선택을 해야하기에 “멀티 쓰레드가 항상 성능이 좋다고 보장할 수 없다”.

사진9: Chrome 내부의 process 분류
브라우저를 제작하는데 process와 thread에 대한 기준이 없다. 참고하는 글이 Chrome 개발 블로그이기에 Chrome기준으로 보면 위 사진과 같이 다수의 process를 사용하며 탭 내부의 화면을 그리고 각 탭마다 별도의 process를 할당한다.

사진10: Chrome 브라우저화면에서 process의 역할
| Process | 설명 |
|---|---|
| Browser Process | chrome 애플리케이션의 일부분(주소창, 북마크, 뒤로가기 앞으로가기 버튼)을 컨트롤. 또한, 보이지 않는 일부분(네트워크 요청, 파일)도 컨트롤 |
| Renderer Process | 웹사이트가 표현되는 탭 내부의 모든 것을 컨트롤 |
| Plugin Process | 웹사이트 플러그인을 관리 |
| GPU Process | GPU관련 일을 전부 담당 |
멀티 쓰레드(프로세스)가 항상 성능이 좋은 것은 아니지만 Chrome은 다음 이점을 가지기 위해서 멀티 프로세스를 채택함:
주소창 입력 및 데이터 판단:
내비게이션 시작
입력 값이 URL로 판별이 되면 로딩 스피너가 돌아가고 DNS조회 후 TLS를 통하여 HTTPS/HTTP 판별여부를 진행(FrontEnd Roadmap - 인터넷 파트2: 브라우저와 DNS: DNS(Domain Name System)란?)

사진11: UI thread와 Network thread간의 통신으로 HTTP 통신 준비
응답 읽기

사진12: TLS 이후 받게 되는 첫 응답값의 헤더(header)
연결 성공 시, 데이터를 받기 시작하며 Browser Process안의 Netrwork thread가 data를 읽기 시작하며 필요에 따라서 MIME Type Sniffing(Axios문제 해결 당시 MIME Sniffing을 알게된 기록)
만약 HTML이면서 언전하다고 판단되면 renderer process에 넘기고 다운로드가 필요한 데이터라면 download manager로 전달

사진13: HTML이 안전한 콘텐츠인지 확인
이 과정에서 SafeBrowsing 검사 진행을 하며 domain과 응답값이 블랙리스트에 있거나 Cross Origin Read Blocking(CORB)를 통해 같은 출처가 아니라면 warning page로 이동
Render Process 찾기
네비게이션 시작
데이터와 renderer process가 준비되었다면 browser process가 renderer process에 IPC 통신을 하여 신호를 전달하고 data stream(응답값들) 또한 전달
renderer process가 전달받았다는 신호가 나오면 네비게이션은 종료되고 documnet 로딩 단계 시작

사진14: Browser Process가 Renderer Process에게 신호 전달
또한 이때, 주소창에 보안 표시와 UI가 반영
초기 렌더링 완료 후
renderer process가 완료했다고 IPC 신호를 browser process에 전달하면 UI thread는 주소창에 loading spinner를 멈춤

사진 15: 초기 페이지 완료 시 Renderer Process가 Browser Process에게 신호 전달
탭 내부에 일어나는 단계는 전부 renderer process가 처리하며 주요 역할은 HTML, CSS, JavaScript를 해석하고 page로 만드는 것이다
Render process가 데이터를 받기 시작하여 HTML을 먼저 Document Object Model(DOM)로 전환
DOM으로 전환 중 preload scanner 또한 작동을 하는데 와 태그를 만나면 미리 source를 불러오는 역할을 해줌

사진16: DOM tree 변환 과정
해석한 DOM과 CSS 정보 기반으로 renderer process의 Main thread는 layout tree를 작성

사진17: Layout Tree 변환 과정
layout tree는 보여지는 정보만 가지고 있을 뿐 화면을 그리는 순서를 가지고 있지 않음
따라서 이 단계에서는 Main thread가 layout tree를 보고 paint할 순서를 기록

사진18: Paint Records 작성
rasterize: layout tree에 있는 정보를 이제 screen에 pixel화 하는 것
compositing:
layer로 나누기 위해서 Main thread가 layout tree를 보고 layer tree를 생성

사신 19: Layout Tree기반으로 Layer Tree 작성
layer tree와 paint 정보가 정해졌으면 Main thread는 Compositor thread에 해당 정보를 전달 하고 Compositor thread에서 layer를 잘게 조게고 Raster thread가 이어받아서 잘게 조게진 조각을 rasterize 후 GPU에 저장

사진20: 화면을 tile로 분할하여 저장
tile들이 rasterized되었다면 Compositor thread에서 tilte에서 drawer quads를 추합하고 compositor frame을 생성
compositor frame이 완성되면 IPC를 통해서 Browser Process로 넘겨주고 화면에 표시

사진21: Tile들을 조합하여 화면에 표시
B-1의 Style, Layout, Paint 작업은 전부 일렬로 진행. 즉, 전 단계가 완료되어야 다음 단계가 실행된다.
또한 해당 작업들은 전부 Main thread에 서 진행이 된다.
따라서, 실행되는 부담이 크고 Main thread에서 작업이 최소화되어야 한다.
JavaScript가 있으면 Main thread의 점유율을 가져가고 중간에 일을 멈추는 것을 알 수 있다. 따라서 화면을 조정하는 작업을 할 때(예를 들어서 animation 처리를 하는 경우) requestAnimationFrame()을 통해서 JavaScript를 파편화 시켜서 화면을 최적화 할 수 있다.


사진22&23: Page Jank 및 requestAnimationFrame() 사용 시의 현상
먼저 Reflow와 Repaint의 정의는:
각 재실행 작업들은 결국 Render Process가 다시 계산하는 작업을 실행하게 되며 Main thread의 점유를 하게 된다.
Main thread 점유 시 다른 일을 못 할 수 있기에 점유율을 최대한 줄이는 것이 좋다.
어떤 것들이 위 작업들을 유발할까?
그러면 어떻게 최적화를 할 수 있을까?
display:none을 통하여 일괄적으로 숨김 후 일괄 수정 후 다시 화면 표시이 글(CSS Triggers List – What Kind of Changes You Can Make)에서 CSS의 어떤 속성이 layout, paint, 또는 composite에 영향을 주는 지 확인이 가능하다.
업무 중 동적으로 변경되는 화면이 있고 시간 또한 있다면 참고하면서 만들기 좋을 것 같다.
Inside look at modern web browser (part 1) | Blog | Chrome for Developers
웹페이지를 표시한다는 것: 브라우저는 어떻게 동작하는가 - 웹 성능 | MDN
매끄럽게 동작하는 브라우저 만들기 - 렌더링 최적화 Reflow, Repaint