반응형

 

CORS는 많이 들어봤는데

CORB란것을 '사이트 격리'에 대해 알아보다가

새로 알게 되었다.

 

참고) 사이트 격리

 

- It ensures that pages from different websites are always put into different processes.

- It also blocks the process from receiving certain types of sensitive data from other site

 

즉, Chrome's Site Isolation effectively makes it harder for untrusted websites to access or steal information from your accounts on other websites.

 

Cross-Origin Read Blocking(CORB)

 

Cross-Origin Read Blocking (CORB) is an algorithm that can identify and block dubious 
cross-origin resource loads in web browsers before they reach the web page.

 

For example, it will block a cross-origin text/html response requested 
from a <script> or <img> tag, replacing it with an empty response instead.

 

출처 : https://developers.google.com/web/updates/2018/07/site-isolation

 

즉, 웹에서 cross origin의 data resource(xml, html, json 등)를 읽어와 사용하지 못하도록 브라우저에서 막는 동작이다.

 

원리 

 

CORB가 어떻게 동작하는지 알아보자.

보통 web client는 서버에 두가지의 요청을 보낸다.

 

  1. data resources such as HTML, XML, or JSON documents
  2. media resources such as images, JavaScript, CSS, or fonts

보통 1번은 SOP & CORS 설정에 따라 브라우저에 의해 blocking 되거나 보이게 된다.

(참고로 2번 media resources들은 cors에 상관없이 요청 가능하다. ex-JSONP)

 

조건 

그리고 CORB는 위 조건을 만족한다면

renderer processa cross-origin data resource를 받아와 사용하는 것을 금지한다.

(a new security feature that prevents the contents of balance.json from ever entering the memory of the renderer process memory based on its MIME type.)

 

참고)

X-Content-Type-Options: nosniff는 Microsoft에서 제안하는 확장 헤더이며 웹서버가 보내는 MIME 형식 이외의 형식으로 해석을 확장하는 것을 제한하는 크로스사이트스크립트 방어법이다.

 

즉, nosniff 옵션이 켜있다면 브라우저는 이게 HTML, XML, JSON중 하나인것으로 Content-type 종류로 인하여 헷갈리지 않고 바로 확정 지을 수 있다.

(가끔 어떤 서버는 이미지에 대해 text/html로 잘못 분류하기도 한다. 이걸 방지 가능)

 

이점 

 

CORB를 사용하면 다음과 같은 이점이 있다.

 

- Mark responses with the correct Content-Type header.

- out of sniffing by using the X-Content-Type-Options: nosniff header.

- 보안! (In browsers with Site Isolation, it can keep such data out of untrusted renderer processes entirely, helping even against side channel attacks like Spectre)

예시

그럼 예시 데모를 한번 보자.

 

https://anforowicz.github.io/xsdb-demo/index.html

 

CORB demo

Demo of CORB This page demonstrates how Cross-Origin Read Blocking (CORB) works. Please see one of the following resources for more information about CORB: Repro steps to trigger CORB: Make sure that CORB is active In Chrome M68 and later CORB is active by

anforowicz.github.io

 

<button> Add 1 <img src="https://www.chromium.org/"> </button>
<button> Add 2 <img src="https://www.w3.org/.../dummy.pdf"> </button>

 

들어가서 버튼을 한번 눌러보면

CORB 차단이 뜬다.

 

위 버튼들은 data resource(text/html, application/pdf) 요청을 cross-origin 서버에 보내는 버튼들이고, CORB에 의해 막히게 된다.

그리고 CORS와 동일하게 정상적인 요청이 왔어도 (status 200) 브라우저에서 막도록 구현된 것을 확인할수 있다.

 

 

tmi)

현재 tistory 스킨에서 영어를 읽으려니 눈이 아프다 -_-;

 

 

함께 읽으면 좋은 글)

 

CORS

https://beomy.github.io/tech/browser/cors/

 

[Browser] CORS란?

이번 포스트에서는 교차 출처 리소스 공유(Cross-Origin Resource Sharing, CORS)에 대해 이야기해보도록 하겠습니다. 아래 사진과 같은 에러를 보신 적이 있으셨을 수도 있습니다.

beomy.github.io

 

reference 

 

https://chromestatus.com/feature/5629709824032768

 

https://stackoverflow.com/questions/18337630/what-is-x-content-type-options-nosniff

 

https://webhack.dynu.net/?idx=20161120.001&print=friendly 

 

https://bingbingba.tistory.com/8

 

https://developers.google.com/web/updates/2018/07/site-isolation

 

Site Isolation for web developers  |  Web  |  Google Developers

Chrome 67 on desktop has a new feature called Site Isolation* enabled by default. This article explains what Site Isolation is all about, why it’s necessary, and why web developers should be aware of it.

developers.google.com

 

반응형
반응형

이 글은 사용자 입력(input)을 받았을 때 컴포지터가 어떻게 부드러운 상호작용을 하는지에 관한 글이다

(출처는 https://developers.google.com/web/updates/2018/09/inside-browser-part4)

 

Inside look at modern web browser (part 4)  |  Web  |  Google Developers

Input event handling with the compositor thread

developers.google.com

 

사용자 입력을 받았을때

 

브라우저 관점에서 입력이란 모든 사용자의 제스처(이벤트)를 의미한다. 스크롤도 이벤트이고, 화면 터치, 마우스 포인터를 올리는거도 입력 이벤트이다.

 

 

화면 터치와 같은 사용자 제스처가 발생했을 때 가장 먼저 제스처를 수신하는 것은 브라우저 프로세스이다. 브라우저 프로세스는 제스처가 어디에서 발생했는지만 알고 있다. 탭 내부의 콘텐츠는 렌더러 프로세스가 처리해야 한다. 

 

그래서 브라우저 프로세스는 이벤트 종류와 좌표값(x,y 등)만 렌더러 프로세스에 넘기게 된다.

렌더러 프로세스는 이벤트 대상과 이벤트 리스너를 실행해 이벤트를 적절히 처리한다.

 

스크롤의 예시로 렌더러 프로세스 내부동작을 알아보자.

 

그림 출처 : https://developers.google.com/web/updates/2018/09/inside-browser-part4#compositor_receives_input_events

 

스크롤할때 레스터화된 레이어를 컴포지터가 합성해 스크롤을 부드럽게 처리한다.

이벤트리스너가 없다면 컴포지터 쓰레드는 메인 쓰레드와 상관없이 스스로 합성해서 프레임을 만들어낼 수 있다.

 

그런데 이벤트가 달려있다면 다르게 동작하게 된다.

합성하는 쓰레드는 컴포지트 쓰레드이고, 

이벤트를 실제로 처리하는 쓰레드는 JS를 동작시키는 메인 쓰레드이다.

어떻게 둘이 상호작용을 하게 될까?

 

고속 스크롤 불가 영역(non-fast scrollable region)

 

JS가 실행되는 작업은 메인 스레드의 영역이므로 이벤트 핸들러가 연결된 영역을 고속 스크롤 불가 영역(non-fast scrollable region)이라고 표시한다. 이 영역에서 이벤트가 발생하면 렌더러 프로세스는 우선 컴포지터 스레드에게 작업을 보내고, 컴포지트 스레드는 입력 이벤트를 메인 스레드로 보내야하는지 정보를 확인 후 넘겨준다.

 

만약 고속 스크롤 불가 영역이 아니라면 컴포지터 스레드는 메인 스레드를 기다리지 않고 새 프레임을 합성한다.

(컴포지터 스레드는 복사된 자신만의 레이어 트리를 가지고 있는다. - pending tree -> active tree?)

 

그렇다면 여기서 한가지 의문점을 가지게 된다.

이벤트 위임을 설정할때는 어떻게 될까?

 

ex)

document.body.addEventListener('touchstart', event => {  
    if (event.target === wantedNode) {
        event.preventDefault();
    }
});

이벤트 위임을 document나 root 등 최상위에 선언했을때

이벤트위임을 최상위에 선언했을경우 다음 그림과 같이 페이지가 전부 고속 스크롤 불가 영역에 속하게 된다.

 

이런 문제를 방지하기 위해 passive : true 옵션을 전달하면 메인스레드에서 이벤트를 받지만, 컴포지터가 메인 스레드의 처리를 기다리지 않고 새 프레임을 만들어도 되는 힌트를 브라우저에 주는 옵션을 줄 수 있다.

ex)

document.body.addEventListener('touchstart', event => {  
    if (event.target === wantedNode) {
        event.preventDefault();
    }
}, {passive: true});

 

JS로 가로로만 스크롤을 제한하고 싶을때 

passive : true 옵션을 주면 부드럽게 스크롤이 된다는거까지는 알았다. 그런데 스크롤을 JS의 event.preventDefault() 함수로 제한한다면 쓰레드가 다르므로 event.preventDefault() 가 실행되기 전 이미 수직 스크롤이 실행될 수도 있다. 그래서 event.cancelable()를 사용하면 스크롤 시작 여부를 확인 가능하다.

document.body.addEventListener('pointermove', event => {
    if (event.cancelable) {
        event.preventDefault(); // block the native scroll
        /*
        *  do what you want the application to do here
        */
    }
}, {passive: true});

 

======

 

역주 : 모질라에 따르면 passive : true는  event.preventDefault()가 내부에서 실행이 안될꺼라는 약속이라는데

위 코드를 실제로 실행해보면 에러가 뜬다.

 

아래 링크 참고

https://developer.mozilla.org/ko/docs/Web/API/EventTarget/addEventListener

위 코드를 복붙해서 실행했을때 나온 오류

https://stackoverflow.com/questions/37721782/what-are-passive-event-listeners

 

What are passive event listeners?

While working around to boost performance for progressive web apps, I came across a new feature Passive Event Listeners and I find it hard to understand the concept. What are Passive Event Listene...

stackoverflow.com

스텍오버플로우에 따르면

By marking a touch or wheel listener as passive, 
the developer is promising the handler won't call preventDefault to disable scrolling. 
This frees the browser up to respond to scrolling immediately without waiting for JavaScript, 
thus ensuring a reliably smooth scrolling experience for the user.

라는데 원글의 예시 코드는 이해를 돕기 위한 '예시'인지 좀 혼란스럽긴 하다.. 

일단 스택오버플로우와 원글의 공통점을 추론해보자면

passive : true를 설정하면 메인 쓰레드(JS)가 작동하지 않고 스크롤 이벤트때 컴포지트 쓰레드가 바로 동작하는 개념은 맞는듯 싶다.

 

======

 

(아무튼 계속 시작)

 

또는 아에 touch-action에서 아예 수직 스크롤 이벤트를 지워버릴수도 있다.

#area {
  touch-action: pan-x;
}

 

이벤트 대상 찾기

 

컴포지터 쓰레드가 메인 스레드로 보낼때 이벤트 대상을 찾는 hit test를 한다.

이벤트가 발생한 좌표에 무엇이 있는지 확인을 위해 paint recoards data를 이용한다.

(브라우저의 렌더링 단계에서 파싱->스타일->layout->paint->composite 에서 paint)

 

(아마 opcacity, transform등의 정보를 따로 담고 있는 property tree의 정보도 참고하기 위해서

paint tree를 참고하는거로 추론?)

 

메인 스레드 이벤트 전송 최소화

 

일반적으로 모니터는 1초당 60번 (60프레임) 화면을 갱신한다. 그리고 애니메이션도 화면 갱신 주기에 맞춰야

부드럽게 움직인다.

 

일반적으로 touchEvent는 초당 60~120회 전달하고, 마우스는 초당 100회정도 전달한다.

즉, 화면 갱신보다 이벤트 갱신 주기가 더 짧아서 이벤트가 뚝뚝 끊겨보이는 상황을 연출할 수도 있다.

 

너무 과도한 호출로 버벅거림을 유발하는 이벤트

 

그래서 메인 호출이 과다해지는것을 막기 위해서 Chrome은 자체적으로 연속적(coalesces continuous)인 이벤트(wheel , mousewheel , mousemove , pointermove , touchmove)는 다음번 requestAnimationFrame() 메서드 실행 직전까지 전송하지 않고 기다리게 된다.

 

keydown, keyup, mouseup, mousedown, touchstart, touchend와 같은 비연속적인(discrete) 이벤트는 즉시 전달된다.

 

한 프레임 안에서 합쳐진 이벤트 정보를 얻기 위해 getCoalescedEvent() 사용

드로잉 앱 같은 경우 프레임 사이 사이 경로가 누락되 선을 매끄럽게 그리지 못할 수도 있다. 이때 getCoalesecedEvents를 사용하면 합쳐진 이벤트의 정보를 얻을 수 있다.

 

 

 

 

reference 

 

https://d2.naver.com/helloworld/6204533

https://developers.google.com/web/updates/2018/09/inside-browser-part4

 

Inside look at modern web browser (part 4)  |  Web  |  Google Developers

Input event handling with the compositor thread

developers.google.com

 

반응형
반응형

주의) 이글은 깁니다...

 

크롬에서 렌더링은 렌더러 프로세스가 담당한다.

이 글과 이전글은 GPU가 실제 클라이언트에서 어떻게 쓰이는지 원리를 알기 위해 찾아보았던 내용이다.

그 내용을 아래에 후술한다.

 

렌더러 프로세스에 관한 이전 글)

https://lodado.tistory.com/19

 

[운영체제] 크롬 웹 브라우저의 구조 (프로세스 & 쓰레드)

자바스크립트는 싱글 쓰레드이지만, 크롬 브라우저의 탭 하나하나는 각각 하나의 프로세스이고 멀티 쓰레드 환경이다. 이전에 썼던 이벤트 루프 관련 글에서 정확히 브라우저의 내부 구조가 어

lodado.tistory.com

 

www.google.com을 검색할때 크롬에서 일어나는일 

 

면접 단골 질문이긴 한데 네트워크 말고 크롬이 하는 일만 집중해서 간단히 살펴보자.

자세한 과정은 아래 링크를 추천한다.

브라우저마다 상세 구현은 다를 수 있기 때문에

'흐름' 을 파악하는 정도면 좋을 것 같다.

 

https://developers.google.com/web/updates/2018/09/inside-browser-part2?hl=ko 

 

모던 웹 브라우저 들여다보기 (파트 2)  |  Web  |  Google Developers

브라우저가 탐색 요청을 처리하는 방법을 학습하십시오.

developers.google.com

 

Brower Process 도식도

브라우저 프로세스는 주소 창, 뒤로 및 앞으로 이동 버튼을 포함한 어플리케이션의 "chrome" 부분을 제어한다.

또한 네트워크 요청 및 파일 액세스와 같은 웹 브라우저의 권한이 부여된 보이지 않는 부분을 제어한다.

 

브라우저 프로세스 내부를 보면

버튼이나 입력창을 그리는 UI 스레드,

인터넷에서 데이터를 수신하기 위해 통신 스택을 건드리는 네트워크 스레드,

파일 같은 것들에 접근하기 위한 스토리지 스레드

등을 가지고 있다. 

 

 

 

Browser Process가 내부 NetWork thread에 브라우저 탐색 과정을 수행하게 시키고, 작업이 완료되면 

Renderer Process에게 IPC를 통해 페이지 렌더를 요청한다.

이후 과정이 우리가 흔히 아는 브라우저의 렌더링 과정이다.

 

Renderer Process가 하는 일 

렌더러 프로세스는 브라우저 탭 안에서 일어나는 모든 일들을 담당한다.

렌더러 프로세스의 핵심 역할은 HTML, CSS 그리고 자바스크립트를 사용자가 인터렉션할 수 있는 웹 페이지로 만드는 것이다.

 

프로세스는 여러개의 쓰레드로 구성되어 있다.

 

Main Thread : 대부분의 코드를 처리한다. (파싱, 렌더 등)

Work Threads : 웹 워커 혹 서비스 워커를 사용할 경우 워커 스레드가 자바스크립트 코드 일부분을 처리한다.

Compositor & Raster Thread  : 렌더러 프로세스 내부에서 페이지를 효율적이며 매끄럽게 렌더하기 위해 실행된다.

compositor와 Raster thread의 역할은 후술한다.

 

브라우저의 렌더링 과정 

웹킷의 동작 과정

이것 또한 표준이 없어서... 세부 구현이 브라우저마다 다를 수 있지만 흐름 자체를 이해하자.

브라우저는 파싱  스타일  레이아웃  페인트  합성  렌더 등의 과정을 거친다. 그 후에 JS나 CSS를 통해 DOM이나 CSS에 변화가 생길 경우 reflow 혹은 repaint 등의 과정을 수행한다.

 

1) 파싱

 

HTML 파싱

 

브라우저가 HTML 을 파싱하고 읽어들이는 과정이다.

렌더러 프로세스가 탐색을 위한 커밋 메세지를 받고 HTML 데이터를 받기 시작할 때, 메인 스레드는 텍스트 문자열 (HTML)을 파싱하기 시작하고 이를 Document Object Model (DOM)으로 변환한다.

DOM은 페이지에 대한 브라우저의 내부 표현일 뿐만 아니라 웹 개발자가 자바스크립트를 통해 상호 작용할 수 있는 데이터 구조 및 API이다.

 

예측 파싱

HTML 문서에 <img> 혹은 <link>등이 있는 경우, 사전 로드 스케너는 HTML 파서에 의해 생성된 토큰들을 살짝 보고 브라우저 프로세스에 있는 네트워크 스레드에게 요청을 보낸다.

 

파싱 차단 리소스

 

파싱 과정에서 자바스크립트가 파싱을 중단시킬수도 있다.

<script> 태그를 만나면 HTML 문서를 파싱하는것을 멈추고 자바스크립트 코드를 로딩, 파싱, 실행한다.

이를 JavaScript는 파싱 차단 리소스(parser blocking resource)라고 부른다.

 

이를 방지하기 위해서는

 

  • <script>를 body 제일 아래에 놓는다 (가장 고전적인 방법)
  • 비동기로 데이터를 내려받고 다운로드가 완료되면 실행되는 async 태그를 사용한다.
  • 비동기로 데이터를 내려받고 파싱이 완료되면 실행되는 defer 태그를 사용한다. (가장 추천)
  • 리소스 우선순위화 - <link rel="preload"> 사용

가장 추천되는 방식은 head에 script + defer attribute이다.

asnyc, defer에 대해서는 아래 글 추천

 

https://guiyomi.tistory.com/101

 

Javascript - script 로딩 시 async vs defer

HTML 파일에서 외부 js 파일을 가져오는 방법은 다음과 같다. 그럼 여기서 궁금한 점이 발생한다. script 태그의 위치는 어디에 위치해야 할까? 보통 브라우저는 HTML 문서를 파싱할 때, 위에서부터

guiyomi.tistory.com

 

CSS 파싱

외부/내부의 스타일시트의 CSS를 해석해 CSSOM 트리를 구성한다.

속성을 주지 않아도 각 element들은 브라우저마다 고유의 css 속성을 가지며, 이것을 인위적으로 통일하거나

다 지우기 위해서 보통 개발할때 normalize.css나 reset.css를 사용한다.

 

렌더 차단 리소스(rendering-blocking-resource)

 

HTML, CSSOM이 완성 이전까지 브라우저는 렌더링을 멈추게 된다.

즉, css를 네트워크에서 빨리 받아오는게 중요하다.

<link rel="preload" as="script" href="super-important.js">
<link rel="preload" as="style" href="critical.css">

preload, preconnect, prefetch 등을 사용해 브라우저에게 우선순위를 알려줄 수 있다.

 

<link href="style.css"    rel="stylesheet">
<link href="style.css"    rel="stylesheet" media="all">
<link href="print.css"    rel="stylesheet" media="print">
<link href="portrait.css" rel="stylesheet" media="orientation:landscape">
<link href="other.css"    rel="stylesheet" media="min-width: 40em">

그리고 미디어 쿼리를 이용해 자신이 사용하는 미디어 타입에 걸맞는 css만 받아오고, 다른 기기의 css는 받아오지 않는 식으로 (용량을 줄여) 최적화 할 수 있다.

 

2) 스타일 

 

dom tree와 CSSOM tree가 생성되었다면 결합해서 Render Tree를 만든다.

렌더링 트리에는 페이지를 렌더링하는 데 필요한 노드만 포함된다.

 

그리고 어떤 렌더 객체는 DOM 노드에 대응하지만 트리의 동일한 위치에 있지 않다. float 처리된 요소 또는 position 속성 값이 absolute로 처리된 요소는 흐름에서 벗어나 트리의 다른 곳에 배치된 상태로 형상이 그려진다. 대신 자리 표시자가 원래 있어야 할 곳에 배치된다.

 

3) 레이아웃(재시작시 Reflow)

 

레이아웃은 요소들의 기하학적인 구조를 찾는 과정이다.

현재 viewport 기준으로 정확히 DOM이 어디있는지 위치, 크기를 계산한다.

 

만약 CSS나 돔의 layout과 관련된 요소(width, font-size 등)가 변경된다면 reflow 과정이 생길수도 있다.

 

추가적으로

 

display: none을 사용하면 렌더링 트리에서 요소가 완전히 제거된다.

visibility : hidden을 사용하면 레이아웃에서 공간을차지하지만 요소가 보이지 않는다.

 

그리고 레이아웃 트리를 순회하면서 속성 트리(property tree)를 만드는 작업이 페인트와 레이아웃 사이에 끼여있다.

속성 트리는 clip, transform, opacity등의 속성 정보만 가진 트리이다. 

최신 Chrome에서는 이런 속성만 별도로 관리하고 각 노드에서는 속성 트리의 노드를 참조하는 방식으로 변경되고 있다.

4) 페인트(재시작시 repaint)

레이아웃 트리를 따라가 페인트 기록을 생성한다.

 

배경 이미지, 텍스트 색상, 그림자등 실제 레이아웃의 수치를 변형시키지 않는 스타일의 변경이 일어나면

repaint만 발생한다.

일반적으로 reflow가 발생되면 repaint도 같이 발생한다.

(레이아웃 수치를 다시 계산해서 배치를 해야하기 때문에)

 

5. 합성(composite)

페이지를 그리는 방법

 

컴포지팅은 한 페이지의 부분들을 여러 레이어로 나누고 그 것들을 각각 레스터화하며 컴포지터 스레드에서 페이지를 합성하는 기술이다. 그리고 만약 스크롤이 발생하면, 레이어들이 이미 레스터되었기 때문에, 해야 할 것은 새로운 프레임을 합성하는 것이다.

 

 

https://developers.google.com/web/updates/2018/09/inside-browser-part3#what_is_compositing

에니메이션은 레이어들을 움직이는 동일한 방식으로 이뤄지고 새로운 프레임을 합성한다.

어떻게 웹 사이트가 여러 레이어로 나뉘는 지 개발자 도구의 Layers panel에서 볼 수 있다.

 

참고) 레스터화와 벡터화

 

레스터화는 각 요소 이미지를 컴퓨터가 이해할 수 있는 비트맵으로 변환하고, 하나의 비트맵으로 합성하는 과정이다.

https://m.blog.naver.com/reductionist101/221567932033

 

래스터, 벡터 차이

래스터(raster)와 벡터(vector)는 컴퓨터가 이미지를 저장하는 방식이며, 둘 사이에는 차이가 있다. 첫 번...

blog.naver.com

 

Layer에 대해서

 

메인 스레드는 레이아웃 트리를 순회하여 레이어 트리를 생성한다. (이 부분은 개발자 도구 성능 탭의 Update Layer Tree 참고)

 

모든 요소들에 대해 레이어를 지정할 수도 있다. 하지만 수많은 레이어를 합성하는 것은 웹페이지의 작은 부분을 매 프레임마다 새로 래스터화하는거보다 느릴 수 있다.

 

그래서 메인 쓰레드를 사용하지 않고 레스터와 컴포지트 하는 방식을 알아보자 (쉬운 말로 GPU를 써보자)

 

 

타일들을 레스터화(비트맵 생성) 시키고 GPU에 전송시키는 레스터 쓰레드들

레이어 트리가 생성되고 페인트 순서가 결정되고 나면, 메인 스레드는 컴포지터 스레드에게 정보를 커밋한다.

그러면 컴포지터 스레드가 각 레이어를 레스터라이즈(=레스터화)한다.

 

컴포지터 스레드는 레이어들을 여러 타일로 쪼개고 각 타일을 다수의 레스터 스레드에게 보낸다.

레스터 스레드들은 각 타일을 레스터화하고 그 것들을 GPU 메모리에 저장한다.

 

컴포지터 스레드는 서로 다른 레스터 스레드들에 대해 우선 순위를 정할 수 있어서 화면 안에 보이는 (혹은 가까이 있는) 것들이 먼저 레스터될 수 있다.

 

쿼드 군집으로 컴포지터 프레임을 생성해 GPU에게 IPC를 사용해 넘긴다.

 

타일들이 레스터되면, 컴포지터 스레드는 쿼드 군집(draw quads) 라 하는 타일 정보를 모아 컴포지터 프레임을 생성한다.

 

드로우 쿼드  메모리에서 타일의 위치 및 페이지 합성을 고려하여 타일을 그릴 페이지의 위치와 같은 정보를 포함합니다.
컴포지터 프레임 한 페이지의 프레임을 나타내는 쿼드 군집의 컬렉션입니다.

 

컴포지터 프레임은 IPC를 통해서 브라우저 프로세스에게 넘어간다. 

즉, 조각조각 내서 IPC로 넘긴다. 이해하면서 내 멘탈도 지금 조각조각 나고 있다.

 

 이 때, 다른 컴포지터 프레임이 브라우저 UI 변화에 따라 UI 스레드에 의해 혹은 확장 기능에 대한 다른 렌더러 프로세스들에 의해 추가될 수 있다. (GPU process는 하나니까.. 근데 이런 경우가 언제 있는지는 잘 모르겠다)

 

이러한 컴포지터 프레임들은 GPU에게 보내져 화면에 보여진다. 만약 스크롤 이벤트가 발생하면, 컴포지터 스레드는 GPU에게 보내질 다른 컴포지터 프레임을 생성한다.

 

이러한 방식의 장점은 메인 스레드의 개입 없이(reflow와 repaint 없이) 컴포지팅이 GPU에 의해 수행된다는 것이다.

 

 

현재 CSS의

  • opacity
  • translate
  • rotate
  • scale
  • will-change 

옵션이 GPU 가속을 지원한다.

그리고 전 글에도 적었지만, 무분별한 GPU 남용은 오히려 해가 된다.

보통은 잘 바뀌지 않는 값과 에니메이션을 레이어를 분리해 지정하는게 좋다. 

(The Animation Process From 1938)

이 영상에서는 배경은 그대로 두고 앞에서 움직여야 하는 전경만 별도의 셀로 만들어서 프레임을 촬영한다. 

-> 크기, 내용은 그대로고 이동(에니메이션)만 하는 element를 지정하는게 좋다

-> 작을수록 좋다

 

함께 읽어보면 좋을 글) 

 

https://docs.google.com/presentation/d/1QRchHprSPW4JVwAUVWmGmq3gmR8nLWrJmGYFzWHW9G4/edit#slide=id.g7b5233544_0274

 

Threaded GPU Rasterization

Threaded GPU Rasterization crbug.com/454500 State of GPU Rasterization (M-42)

docs.google.com

 

https://web.dev/why-speed-matters/

 

속도가 왜 중요합니까?

사용자 경험에서 속도는 중요한 역할을 합니다. 모바일 속도로 인한 지연은 실망스러울 뿐만 아니라 비즈니스 결과에도 부정적인 영향을 미칠 수 있습니다.

web.dev

 

https://web.dev/fast/

 

빠른 로드 시간

사이트 성능을 높이기 위한 기술.

web.dev

 

reference 

https://d2.naver.com/helloworld/5237120

https://d2.naver.com/helloworld/59361

https://junilhwang.github.io/TIL/Javascript/Design/Vanilla-JS-Virtual-DOM/#_1-%E1%84%87%E1%85%B3%E1%84%85%E1%85%A1%E1%84%8B%E1%85%AE%E1%84%8C%E1%85%A5-%E1%84%85%E1%85%A9%E1%84%83%E1%85%B5%E1%86%BC-%E1%84%80%E1%85%AA%E1%84%8C%E1%85%A5%E1%86%BC

 

Vanilla Javascript로 가상돔(VirtualDOM) 만들기 | 개발자 황준일

Vanilla Javascript로 가상돔(VirtualDOM) 만들기 본 포스트는 React와 Vue에서 사용되고 있는 가상돔(VirtualDOM) 직접 만들어보는 내용이다. 그리고 이 포스트를 읽기 전에 Vanilla Javascript로 웹 컴포넌트 만들

junilhwang.github.io

 

https://developers.google.com/web/updates/2018/09/inside-browser-part3?hl=ko 

 

모던 웹 브라우저 들여다보기 (파트 3)  |  Web  |  Google Developers

브라우저 렌더링 엔진의 내부 작동 방식

developers.google.com

https://velog.io/@itssweetrain/Reflow-%EC%99%80-Repaint

 

성능 최적화와 관련해서 : reflow 와 repaint

이렇게 렌더 트리 생성이 끝나면 배치가 시작된다. 레이아웃 단계는 트리를 생성하면서 계산된 노드와 스타일을 기기의 뷰포트에서 어떤 위치에서 어떻게 보이도록 하는지 결정하는 단계입니

velog.io

 

https://d2.naver.com/helloworld/2061385

 

 

https://medium.com/@cwdoh/%ED%94%84%EB%A1%A0%ED%8A%B8%EC%97%94%EB%93%9C-%EA%B0%9C%EB%B0%9C%EC%9E%90%EB%A5%BC-%EC%9C%84%ED%95%9C-%ED%81%AC%EB%A1%AC-%EB%A0%8C%EB%8D%94%EB%A7%81-%EC%84%B1%EB%8A%A5-%EC%9D%B8%EC%9E%90-%EC%9D%B4%ED%95%B4%ED%95%98%EA%B8%B0-4c9e4d715638

 

프론트엔드 개발자를 위한 크롬 렌더링 성능 인자 이해하기

3년 전에 개인 블로그에 적었던 글이라 이미 보신 분들도 있으리라 생각됩니다만, 미디엄에서 이전의 기술관련 글들을 같이 관리할 겸 같이 포스팅하기로 하였습니다. :)

medium.com

 

반응형
반응형

자바스크립트는 싱글 쓰레드이지만, 크롬 브라우저의 탭 하나하나는 각각 하나의 프로세스이고 멀티 쓰레드 환경이다. 

이전에 썼던 이벤트 루프 관련 글에서 정확히 브라우저의 내부 구조가 어떻게 구성되었는지 궁금해서 찾아보았다. 

 

참고) 이전글

https://lodado.tistory.com/16

 

[이벤트루프] 자바스크립트에서 정확한 타이머 구현?

*잘못된 부분이 있으면 피드백 주시면 감사하겠습니다! 자바스크립트에서 타이머 이벤트를 쓸 수 있는 방법으로는 setTimeout, setInterval 두가지가 있다. 이 함수들이 어떻게 비동기를 지원할까? 자

lodado.tistory.com

컴퓨터 아키텍처 3개 레이어 - 브라우저가 돌아가는 환경

 

하단부의 Machine Hardware, 중앙부의 운영 체제, 상단부의 어플리케이션.

 

브라우저가 돌아가는 환경을 이해하기 위해서는 컴퓨터의 전반적인 구조를 이해할 필요가 있다.

 

Machine Hardware (스마트폰, 컴퓨터 등)

 

물리적으로 구현된 하드웨어 위에서 컴퓨터가 동작

실제 작업을 물리적으로 처리하는 공간이다.

최근에는 브라우저에서 단순 CPU를 넘어서서 고속 렌더링, 에니메이션을 처리하기 위해 추가적으로 GPU라는 개념이 등장했다.

 

CPU 

Central Processing Unit - CPU

 

CPU는 컴퓨터의 뇌라고 볼 수 있다.

다양한 작업을 실제적으로 처리하는 공간이다.

최근엔 싱글 CPU를 넘어서서 멀티 코어등 다양한 방식을 이용해 '병렬성'을 지원하려는 연구가 활발하다.

 

GPU

 

Graphics Processing Unit - GPU

최근 브라우저에서 GPU를 이용하려는 연구도 활발하다.

GPU는 공장이라고 비유할 수 있다.

CPU는 다양한 작업을 유연하게 처리하는데 특화되어 있다면

GPU는 연산을 수많은 코어에서 동시에 처리하는데 특화되어 있다.

GPU 가속 연산 덕분에 CPU 하나로는 오래 걸릴 연산을 금방 끝낼 수 있다.

 

GPU가 연산을 하기 위해서는 CPU가 GPU에 데이터를 전송해줘야 연산이 가능하다.

이것을 비유하자면 CPU는 배송 트럭이라고 생각하고, GPU는 공장이라고 비유해보면 좋을것 같다.

 

GPU Bottleneck - 병목현상

CPU가 배송(I/O, 효율적인 프로그래밍)를 빨리 해줘야 공장이 100% 효율로 가동 가능하다.

공장이 최신식(GPU의 성능이 매우 좋아도)이라도 CPU의 배송이 느리다면 제 효율을 낼 수 없다.

그리고 반대로 배송(CPU의 성능이 매우 좋아도)이 엄청 빨라도 공장의 효율이 좋지 않다면 제 효율을 낼 수 없다.

 

요약하자면 둘 다 중요하다.

안드로이드 같은 경우 웹앱을 사용할 경우

GPU 연산이 좋다고 모든 연산을 위임하다보면 위 GPU Bottleneck 현상 혹은 너무 많은 작업으로 오히려 CPU만 사용할때보다 느려질 수 있다.

 

그리고 하드웨어적인 한계가 있기 때문에 CPU, GPU의 성능을 아무리 올려도 언젠간 한계에 부딫치게 된다.

프론트엔드 엔지니어가 관여할 수 있는 부분은 '렌더링 최적화' 등 주어진 자원 내에 최대의 효율을 내는게 주 업무다.

 

Operating System (윈도우, 리눅스, 안드로이드 등)

 

소프트웨어적으로 구현된 운영체제 위에서 어플리케이션이 동작 

(운영체제는 하드웨어와 이용자 사이에서 쉽게 이용할 수 있도록 인터페이스 역할을 한다. 윈도우가 왜 이름이 '윈도우'인지 생각해보면 좋을듯!)

 

Application (브라우저 - 크롬, 오페라 등)

 

우리가 사용하는 브라우저 어플리케이션이다. 운영체제가 지시하는 메커니즘에 따라 CPU & GPU를 동작 시키게 요청한다. 

동작(프로그래밍)을 잘 시키냐에 따라 브라우저의 제 성능을 이끌어낼 수 있다. 

 

프로세스 & 쓰레드

 

그리고 브라우저 아키텍처를 이해하기 이전에 프로세스 & 쓰레드 구조를 이해할 필요가 있다. 

이 부분은 면접 단골질문이기도 하고 학교에서 많이 배우므로 간략하게 설명하고 넘어가겠다.

 

프로세스 

 

프로세스는 운영체제로부터 자원을 할당받은 작업의 단위이다.

즉, 어플리케이션 하나가 프로세스 하나가 될 수 있다.

 

참고) 프로그램에 대해

 

더보기

프로그램은 어떤 작업을 위해 실행 할 수 있는 파일을 말하며 메모리구조에서 code 영역에 있는 실제 물리적 파일을 뜻한다.

프로세스는 컴퓨터에서 연속적으로 실행되고 있는 컴퓨터 프로그램을 뜻하며 메모리에 올라와 실행되고 있는 프로그램의 인스턴스이다.

 

즉, 프로그램(passive) <-> 프로세스(active)관계라고 할 수 있다.

 

쓰레드 

 

쓰레드는 프로세스 내에서 운영체제로부터 할당받는 자원을 실행하는 단위이다.

프로세스 내부에서 여러개가 생길 수 있다.

 

그외 자세한 정보는 다음 링크 추천 

https://gmlwjd9405.github.io/2018/09/14/process-vs-thread.html

 

[OS] 프로세스와 스레드의 차이 - Heee's Development Blog

Step by step goes a long way.

gmlwjd9405.github.io

 

프로세스와 쓰레드 생성 과정

 

process 내부의 쓰레드들

 

어플리케이션이 실행되면 프로세스가 생성되고,

프로세스는 작업을 위해 쓰레드(들)을 생성 할 수 있다.

그리고 OS는 프로세스에게 메모리 한 조각을 주고 모든 상태 정보를 고유 메모리 공간에 저장할 수 있게 한다. 어플리케이션이 끝나면 프로세스도 사라지고 OS가 메모리를 해제한다.

 

(개인적 생각으로 여기서 말하는 메모리는 RAM 메모리를 뜻하는것으로 추론된다.)

프로세스간 통신 - Inter Process Communication (IPC)

 

IPC

그리고 프로세스는 다른 프로세스에게 별도의 작업을 수행하도록 요청 혹은 통신이 가능하다. 많은 어플리케이션이 이 방식을 채택하고 있어 워커 프로세스가 무응답 상태에 빠지더라도 어플리케이션의 다른 부분을 수행하고 있는 프로세스들을 종료할 필요 없이 해당 프로세스만 재시작할 수 있다.

 

IPC에 대한 정보는 다음 링크 추천

https://jwprogramming.tistory.com/54

 

IPC의 종류와 특징

IPC(Inter Process Communication) - 프로세스 간 통신에 대하여 종류와 특징들에 대하여 살펴보겠습니다. [리눅스 커널 구조] - 위 그림처럼 Process는 완전히 독립된 실행객체입니다. 서로 독립되어 있다

jwprogramming.tistory.com

 

브라우저 아키텍처

 

다른 여러 브라우저 구조들

중요한점은 브라우저를 구현하는 '표준'이 없기 때문에 브라우저(IE, 오페라, 웨일, 크롬 등등..)마다 내부 작동 방식이 다를 수 있다.

 

그래서 공통적인 흐름을 이해하는것이 중요하다. (ex : 프로세스 & 쓰레드 구조로 동작하는구나!)

이 글은 2018년 기준 크롬 브라우저를 기준으로 설명한다.

 

크롬의 멀티 프로세스 아키텍처 도식도

 

크롬은 멀티 프로세스 아키텍처를 이용한다.

*중요점 : 크롬은 여러개의 렌더러 프로세스를 가질 수 있다(보통 탭 하나당 하나).

 

각 중요한 프로세스의 설명은 다음과 같다.

프로세스 설명
브라우저 주소 창, 뒤로 및 앞으로 이동 버튼을 포함한 어플리케이션의 "chrome" 부분을 제어합니다.
또한 네트워크 요청 및 파일 액세스와 같은 웹 브라우저의 권한이 부여된 보이지 않는 부분을 제어합니다.
렌더러 웹사이트가 디스플레이 될 때 탭 안의 모든 것 담당.
플러그인 플래시와 같은 웹사이트가 사용하는 모든 플러그인 담당.
GPU 다른 프로세스와 분리된 GPU 작업을 제어합니다. GPU는 여러 앱의 요청을 제어하고 동일한 표면에 표시하기 때문에 다른 프로세스로 분리됩니다.

 

멀티 프로세스 아키텍처의 장점

 

그럼 왜 이런 멀티 프로세스 구조를 가질까?

 

개별 탭에서 실행되는 여러 프로세스의 도식도;

 

보통 탭 하나당 하나의 프로세스를 가진다. 

(추가적으로 사이트 격리 옵션이 켜지고 iframe이 내부에서 실행되면 하나의 개별 Renderer 프로세스를 또 가진다)

 

참고)

https://blog.chromium.org/2017/05/improving-extension-security-with-out.html

 

Improving extension security with out-of-process iframes

Security is critical to Chrome, and many features protect Chrome users as they browse the web. Google Safe Browsing warns users away from ...

blog.chromium.org

 

만약 크롬이 단일 프로세스 환경이고 renderer process가 다중 쓰레드 환경이라면 한 탭이 고장이 나게 되면 모든 탭에 영향을 끼치게 된다. (메모리 영역에서 stack을 제외한 heap, code, data 등 여러 영역을 공유하기 때문?) 

 

그런데 다중 프로세스 환경이라면 탭이 하나 고장한 경우 그냥 닫아버리고 다른 탭으로 이동하면 된다.

 

그외 장점으로는 보안 및 샌드박싱 (운영체제는 프로세스의 권한을 제한하는 기능을 제공)이 있다.

 

메모리 공간 절약

 

최종적인 크롬의 아키텍처

그런데 각 프로세스가 메모리 공간을 할당받아 사용하다보면 메모리 부족 현상이 일어날수도 있고 효율적이지 않다.

그래서 크롬이 고성능 장치에서 실행될 때에는 안정성을 위해 각 서비스를 별개의 프로세스로 분리하고, 자원이 부족한 장치에서는 서비스를 하나의 프로세스로 합쳐 메모리 점유를 낮추는 메커니즘이 들어가 있다.

 

즉, 크롬에서 최대 프로세스 개수에 제한을 두었다.

이 구조는 안드로이드에서도 구현되어 있어 유사한 프로세스를 합쳐 메모리 점유를 줄이는 방식을 실행한다.

 

기타 브라우저의 동작 방식

 

전반적으로 mutli process architecture를 따르는 듯하다.

 

IE8

 

 

 

크롬의 브라우징 프로세스와 렌더링 프로세스 두개를 심플하게 가지는거 같다.

One mainframe process

Zero or multiple tab processes

tab process의 경우 RAM 크기에 따라 자동으로 크기가 조절된다.

 

Firefox

 

Firefox의 경우엔 멀티 프로세스 아키텍처인것은 크롬과 동일하다. 다만 4개까지의 다중 프로세스를 허용하고 이후 

탭의 경우는 구글과 비슷하게 기존 프로세스 내부에서 메모리 영역을 공유한다.

 

Chrome using 1.77x more RAM than Firefox in 64-bit and 2.44x in 32-bit mode. (모질라의 주장에 따르면!)

 

모질라의 주장에 따르면 자기들이 메모리를 제일 적게 쓴다고 하는데

프로세스를 4개까지만 만드니까 당연한 내용이다 😂

 

 

같이 읽어보면 좋을 글)

https://levelup.gitconnected.com/how-web-browsers-use-processes-and-threads-9f8f8fa23371

 

How web browsers use Processes and Threads

A process can be described as an application’s executing program. A thread is the one that lives inside of process and executes any part…

levelup.gitconnected.com

 

https://medium.com/@cwdoh/%ED%94%84%EB%A1%A0%ED%8A%B8%EC%97%94%EB%93%9C-%EA%B0%9C%EB%B0%9C%EC%9E%90%EB%A5%BC-%EC%9C%84%ED%95%9C-%ED%81%AC%EB%A1%AC-%EB%A0%8C%EB%8D%94%EB%A7%81-%EC%84%B1%EB%8A%A5-%EC%9D%B8%EC%9E%90-%EC%9D%B4%ED%95%B4%ED%95%98%EA%B8%B0-4c9e4d715638

 

프론트엔드 개발자를 위한 크롬 렌더링 성능 인자 이해하기

3년 전에 개인 블로그에 적었던 글이라 이미 보신 분들도 있으리라 생각됩니다만, 미디엄에서 이전의 기술관련 글들을 같이 관리할 겸 같이 포스팅하기로 하였습니다. :)

medium.com

 

reference 

 

https://wvganjana.medium.com/how-web-browsers-use-process-threads-67e156abb3c5

 

How web browsers use Process & Threads

As we all know Chrome and Firefox both using multi-threading in architecture. But they support it in different ways.

wvganjana.medium.com

 

https://www.wepc.com/tips/cpu-gpu-bottleneck/

 

CPU and GPU Bottleneck: A Detailed Explanation

Have you ever experienced playing a game and you get sudden FPS drop from time to time? The next second, you’re dead.. If you try to observe, these sudden

www.wepc.com

 

https://developers.google.com/web/updates/2018/09/inside-browser-part1?hl=ko 

 

모던 웹 브라우저 들여다보기 (파트 1)  |  Web  |  Google Developers

브라우저에서 사용자 코드를 하이레벨 아키텍처부터 렌더링 파이프라인 세부 기능에 이르는 기능성 웹사이트로 전환하는 방법

developers.google.com

 

반응형

+ Recent posts