DevTools Performance로 렌더링 병목 추적하기
Reference
앞서 DOM, CSSOM, Render Tree가 어떻게 결합되어 화면을 그리는지 살펴봤다. 이제는 실제 브라우저가 렌더링하는 과정을 직접 관찰하고 병목을 찾는 방법을 알아보자 👀 !
💡 Performance 탭은 이론으로 배운 HTML 파싱 → Style 계산 → Layout → Paint → Composite
과정이 실시간으로 어떻게 일어나는지 보여주는 도구다.
1. Performance 탭이란?
Performance 탭은 브라우저가 실제로 Recalculate Style → Layout → Paint → Composite
을 어떻게 처리했는지를 타임라인 기반으로 시각화해주는 도구이다.
다음과 같은 것을 확인할 수 있다:
- 한 프레임(frame)이 언제, 어떤 이유로 느려졌는지
- JavaScript, Layout, Paint, Composite 각 단계의 수행 시간
- 애니메이션, 스크롤, 이벤트 핸들링 중 CPU/GPU 부하 정도
💡 즉, Render Tree
가 실제로 픽셀로 변환되는 과정을 실시간으로 추적하는 곳이다
2. 기본 사용 방법
DevTools
- Performance 탭 선택, ⏺️ Record 버튼 클릭
- 페이지를 새로고침하거나, 애니메이션/스크롤 등 실제 상호작용 수행
- ⏹️ 버튼을 다시 눌러 기록 중단
Reload + record
옵션을 선택하면 페이지 초기 로딩부터 자동으로 기록 가능
3. 성능 분석 타임라인 구조
Performance 탭을 열면 상단부터 다음과 같은 영역이 나타난다.
주요 영역 | 설명 |
---|---|
FPS 그래프 | 초당 프레임 (녹색이 높을수록 부드럽다) |
Main Thread | JS 실행, Style 계산, Layout, Paint, Composite 흐름 |
Frames 섹션 | 각 프레임이 얼마의 시간(16ms 이내)을 소비했는지 표시 |
Bottom-Up / Call Tree | 어떤 함수/작업이 가장 많은 시간을 썼는지 분석 |
4. 렌더링 파이프라인의 주요 이벤트
앞서 배운 렌더링 과정이 Performance 탭에서는 다음과 같은 이벤트로 나타난다.
이벤트 이름 | 설명 | 원인 | 관련 개념 |
---|---|---|---|
Recalculate Style | CSS 변경 감지 후 스타일 재계산 | class 추가, inline style 변경 | CSSOM |
Layout | 요소의 위치·크기 다시 계산 | DOM 구조 변경, 크기 조정 | Render Tree |
Paint | 픽셀 다시 그리기 | 색상, 그림자, 테두리 변경 | Painting |
Composite Layers | GPU에서 레이어 합성 | transform/opacity 변경 | Composite |
Evaluate Script | JS 실행 | 무거운 연산, 이벤트 핸들러 등 | DOM 조작 |
💡 Recalculate Style → Layout → Paint → Composite
가 과도하게 반복된다면 불필요한 Reflow/Repaint 루프 가능성이 높다.
5. 병목 구간 읽기
Main Thread의 색상별 의미를 파악하면 병목 지점을 쉽게 찾을 수 있다.
색상 | 이벤트 | 의미 |
---|---|---|
🟡 노란색 | JavaScript | 메인 스레드를 점유 중 (렌더링 차단 가능) |
🟣 보라색 | Layout (Reflow) | DOM 구조·크기 변경 빈번 → 성능 저하 |
🟢 초록색 | Paint (Repaint) | 배경색, 그림자, 테두리 재그리기 비용 과다 |
🔵 파란색 | Composite | GPU 합성만 발생 → 성능 양호 ✅ |
- 색상은 DevTools 테마(라이트/다크)나 버전에 따라 다를 수 있다.
6. 예시: Layout Thrashing 탐지
// bad: 읽기와 쓰기가 반복되어 Layout이 100번 발생
for (let i = 0; i < 100; i++) {
box.style.width = box.offsetWidth + 1 + "px"; // 읽기 → 강제 Layout → 쓰기...
}
- Recalculate Style / Layout 이벤트가 100회 이상 반복 표시됨
- FPS 그래프는 급격히 떨어짐 (빨간색 구간 발생)
// good: 읽기와 쓰기 분리
const width = box.offsetWidth; // 읽기 1회
for (let i = 0; i < 100; i++) {
box.style.width = width + i + "px"; // 쓰기만 반복
}
- Performance 탭에서 다시 측정하면 Layout이 1~2회로 줄어들고 FPS가 안정화된다.
7. FPS와 프레임 분석
Performance 탭의 상단 Frames 섹션을 보면 각 프레임의 색상으로 상태를 구분할 수 있다.
색상 | 의미 |
---|---|
🟢 녹색 | 60fps 이상 — 부드럽게 렌더링 중 |
🟡 노랑/주황 | 30~59fps — 약간의 지연 |
🔴 빨강 | 30fps 이하 — 프레임 드랍 발생 |
- 🕒 1초(1000ms)를 60프레임으로 나누면 약 16.67ms
- 따라서 각 프레임이 16ms 안에 완료되어야 60fps가 유지된다.
8. 실전 분석 팁
분석 항목 | 확인 위치 | 개선 포인트 |
---|---|---|
JS 실행 시간 | Main → Scripting | 비동기 처리 / Web Worker |
Layout 빈도 | Main → Rendering | DOM 변경 최소화 |
Paint 빈도 | Main → Painting | CSS 단순화 / transform 활용 |
Composite 빈도 | Compositor Thread | GPU-friendly 속성 사용 |
FPS | Frames 그래프 상단 | 60fps 근처 유지 목표 |
9. 실습: transform vs top 비교
Case 1: top 사용 (Reflow 발생)
element.style.top = "100px";
- Performance 결과: Layout + Paint 발생 (메인 스레드 부하 ↑)
- FPS 저하 가능성 높음
Case 2: transform 사용 (GPU 합성)
element.style.transform = "translateY(100px)";
- Performance 결과: Composite만 발생 (GPU 처리, FPS 유지)
- Layout/Paint 이벤트가 사라짐
💡 DevTools Summary 탭에서 두 코드를 비교하면 성능 차이가 명확히 보인다.
정리
핵심 포인트 | 설명 |
---|---|
Performance 탭 | 렌더링 과정을 실시간으로 시각화 |
Recalculate Style / Layout / Paint | 병목의 3대 원인 |
Composite | GPU 합성 단계 — 성능에 유리 |
JS 점유 시간 | 메인 스레드 블로킹의 주요 원인 |
FPS 모니터링 | 60fps 근처 유지 여부 판단 기준 |
💡 요약
- Performance 탭은
DOM → CSSOM → Render Tree → 픽셀
과정을 실시간으로 관찰하는 도구다. - Reflow·Repaint가 어디서 발생하는지 색상별로 시각적 확인 가능.
- transform, opacity, will-change를 활용해 Composite 중심 구조로 설계하면 병목이 사라진다.
- 최종 목표: Main Thread 부하 ↓, GPU 처리 ↑, 안정적 60fps 유지
💡 최종 목표
렌더링 병목을 눈으로 확인하고, Main Thread 부하를 줄여 GPU 합성 중심 구조로 전환하는 것.
🎯 이는 브라우저 내부 렌더링 시리즈의 핵심 결론이다.