← Blog
최적화

크롬 개발자도구 Performance 탭 읽는 법

한 줄 요약

웹 페이지의 로딩·렌더링·상호작용 과정에서 일어나는 모든 작업(스크립트 실행, 스타일 계산, 레이아웃, 페인팅, 네트워크 등)을 시간 축으로 시각화해서 성능 병목 구간을 찾아내고 최적화하는 도구.


왜 알아야 했나

  • 기능 구현에만 집중하다 보면 성능 최적화는 뒤로 밀리기 쉬운데, 어느 순간 "왜 이렇게 느리지?"를 감이 아니라 데이터로 진단해야 하는 순간이 온다.
  • Network 탭은 "리소스가 언제, 얼마나 걸려 받아졌나"만 보여주지만, Performance 탭은 받은 이후 브라우저가 그걸 처리하면서 어디서 시간을 쓰는지까지 보여준다.
  • 구체적으로 이런 상황에서 필요했다:
    • 버튼 클릭 후 반응이 느리거나 이벤트 처리 시간이 길 때
    • 애니메이션·스크롤이 뚝뚝 끊길 때 (프레임 드롭)
    • 특정 DOM 조작이나 JS 코드가 메인 스레드를 막을 때
    • 페이지 초기 렌더링(FCP, LCP)이 느릴 때

핵심 개념

Performance 탭이란?

  • 웹 애플리케이션의 성능을 분석·최적화하는 도구.
  • 페이지 로딩 및 사용자 상호작용 중 발생하는 모든 작업을 시각적으로 확인 가능.
  • 애니메이션, 스크롤 성능, JavaScript 실행 최적화 등 다양한 성능 문제 디버깅에 유용.
  • 📌 덧붙임: 핵심은 "메인 스레드(Main Thread)는 하나뿐"이라는 사실이다. JS 실행, 스타일 계산, 레이아웃, 페인팅이 모두 이 한 스레드에서 순서대로 일어나기 때문에, 한 작업이 오래 걸리면 화면이 멈춘다(=병목). Performance 탭은 결국 이 메인 스레드를 들여다보는 도구라고 생각하면 이해가 쉽다.

상단 컨트롤 버튼

버튼이름역할
녹화(Record)성능 기록 시작. 다시 누르면(■) 중지
🔄Record and Reload페이지를 새로고침하며 초기 로드 성능을 자동 기록
Clear기록한 데이터 삭제·초기화
Download녹화 데이터를 파일로 저장(공유·재분석용)
Screenshots스크린샷기록 중 페이지 상태를 캡처해 시간별 변화 확인
Memory메모리메모리 사용량 기록 → 메모리 누수 분석

성능 기록하는 2가지 방법

1. 녹화 버튼 (●) — 상호작용 분석용

  • 페이지 로드 이후 발생하는 문제(클릭, 스크롤, 애니메이션 등) 디버깅에 적합.
  • 사용 순서: Performance 탭 열기 → ● 클릭 → 분석할 동작 수행 → ■ 클릭으로 중지 → 데이터 분석.

2. Record and Reload (🔄) — 초기 로드 분석용

  • 새로고침과 함께 페이지 로딩 과정의 문제(FCP, LCP, 리소스 로드, 서버 응답 등)를 디버깅.
  • 사용 순서: 🔄 클릭 → 자동 새로고침 + 데이터 수집 → 완료 시 자동 중지 → 초기 로드 데이터 분석.

성능 보고서 구조

① 상단 타임라인 (Overview)

페이지 로드·상호작용 동안의 주요 성능 데이터를 요약.

  • CPU 타임라인: CPU 사용량 그래프. JavaScript(노란색), 레이아웃(보라색) 등 작업 유형별로 CPU가 얼마나 쓰였는지 표시. 과도하게 치솟는 구간 = 병목 후보.
  • NET (Network): 네트워크 요청·응답 시간 표시.

② 메인 작업 타임라인 (Main Section)

  • Network: 각 리소스(HTML/CSS/JS/이미지/API)가 언제 시작·완료·대기했는지 시각화. 순차 로드인지 병렬 로드인지 확인 가능.
  • Frames: 초당 렌더링 프레임(FPS)을 시각화. 프레임 드롭(낮은 FPS) 위치와 프레임별 작업 시간을 확인 → 렌더링 최적화에 유용. (📌 덧붙임: 부드러운 화면은 보통 60FPS, 즉 프레임당 약 16.7ms 안에 작업이 끝나야 한다. 이걸 넘으면 끊김으로 느껴진다.)
  • Timings: 페이지 로딩 중 주요 이벤트의 타이밍 표시. DCL·FCP·LCP 간 간격을 분석해 병목을 파악.
  • Layout Shifts: CLS(누적 레이아웃 이동) 관련 정보. 레이아웃이 갑자기 밀린 위치·정도를 보여줌. CLS가 높으면 UX 저하.
  • Main: 메인 스레드 작업을 타임라인으로 표시. 병목 구간을 찾는 가장 핵심 영역.

주요 로딩 지표 (Timings)

약자풀네임의미
DCLDOMContentLoadedDOM이 완전히 파싱된 시점
FPFirst Paint화면에 첫 픽셀이 렌더링된 시점
FCPFirst Contentful Paint텍스트·이미지 등 콘텐츠가 처음 렌더링된 시점
LCPLargest Contentful Paint가장 큰 콘텐츠가 렌더링된 시점
TTITime to Interactive페이지가 실제로 사용 가능한 상태가 되는 시간

Main의 작업 범주(렌더링 파이프라인 순서대로)

범주설명
Parse HTMLHTML을 파싱해 DOM 생성
Evaluate ScriptJavaScript 코드 실행
StyleCSS 계산
LayoutDOM 요소의 위치·크기 계산
Painting / Compositing요소를 화면에 렌더링

③ 하단 탭들

  • Summary: 전체 작업 시간 분포를 원형 차트로 요약. 각 작업이 전체 시간에서 차지하는 비율을 한눈에 파악.
  • Bottom-up: 가장 낮은 레벨의 함수 호출부터 시작해 상위 작업까지 시간 소비를 분석. 어떤 함수가 시간을 많이 잡아먹는지 찾기 좋음.
  • Call Tree: 호출 계층을 위 → 아래(상위 함수 → 하위 함수)로 정리. 호출 흐름·경로 추적에 유용.
  • Event Log: 발생한 이벤트를 시간순으로 나열. 작업 발생 시점·순서로 문제 원인 추적.

Summary 원형 차트 색상 의미

색상범주의미
연한 파란색Loading리소스를 네트워크로 다운로드하는 시간
노란색ScriptingJS 실행, 이벤트 핸들러 처리, DOM 동적 조작 시간
보라색RenderingCSS 스타일 계산 + 레이아웃 변환(화면 표시 준비)
초록색Painting픽셀 데이터 생성 후 화면에 그리는 작업
진한 회색System브라우저 내부 처리 시간(직접 최적화 어려움)
연한 회색IdleCPU 대기 시간 (높으면 오히려 효율적이라는 신호일 수 있음)
흰색Total모든 작업의 총합 시간 (예: 약 3123ms = 로딩 완료까지 걸린 시간)

Summary로 병목 진단하는 법

  • Scripting이 많다 → JavaScript 최적화 필요
  • Rendering이 많다 → DOM 구조 간소화 / 스타일 최적화 필요
  • Loading이 많다 → 네트워크 요청 병렬화 / 리소스 크기 최적화 필요

Self Time vs Total Time (Bottom-up·Call Tree·Event Log에서)

용어의미
Self Time함수 자체가 직접 소비한 시간 (하위 함수 호출 시간 제외). 함수 자체의 성능 문제 확인용
Total TimeSelf Time + 모든 하위 작업 실행 시간. 이 함수가 상위 프로세스에 끼치는 영향 확인용
Activity작업의 유형 또는 실행된 특정 활동

예시 / 코드

성능 기록 자체는 코드가 아니라 UI 조작이지만, "메인 스레드를 막는 코드"가 어떤 것인지 감을 잡으면 보고서 해석이 쉬워진다.

// ❌ 나쁜 예: 동기적으로 무거운 계산 → 메인 스레드 블로킹
// Performance 탭 Main에서 노란색(Scripting) 긴 막대로 나타나고, FPS가 떨어진다.
button.addEventListener('click', () => {
  let result = 0;
  for (let i = 0; i < 1_000_000_000; i++) {
    result += Math.sqrt(i);
  }
  console.log(result);
});

// ✅ 개선 예 1: 작업을 잘게 쪼개 메인 스레드 양보
function chunkedWork(total, chunk = 1_000_000) {
  let i = 0, result = 0;
  function next() {
    const end = Math.min(i + chunk, total);
    for (; i < end; i++) result += Math.sqrt(i);
    if (i < total) {
      // requestIdleCallback / setTimeout 으로 다음 프레임에 양보
      requestIdleCallback(next);
    } else {
      console.log(result);
    }
  }
  next();
}

// ✅ 개선 예 2: 무거운 계산은 Web Worker로 분리해 메인 스레드를 비움
const worker = new Worker('heavy.js');
button.addEventListener('click', () => worker.postMessage({ total: 1_000_000_000 }));
worker.onmessage = (e) => console.log(e.data);
// ❌ 레이아웃 스래싱(Layout Thrashing): 읽기/쓰기를 번갈아 → 강제 동기 리플로우
// Performance 탭 Main에서 보라색(Rendering/Layout) 막대가 반복적으로 길게 찍힌다.
items.forEach((el) => {
  const h = el.offsetHeight;   // 읽기(레이아웃 강제 계산)
  el.style.height = h + 10 + 'px'; // 쓰기(레이아웃 무효화) → 다음 읽기에서 또 재계산
});

// ✅ 개선: 읽기를 모아서 먼저, 쓰기를 나중에
const heights = items.map((el) => el.offsetHeight); // 읽기 일괄
items.forEach((el, i) => { el.style.height = heights[i] + 10 + 'px'; }); // 쓰기 일괄

헷갈렸던 점

  • Network 탭 vs Performance 탭: Network는 "리소스 다운로드 타이밍"만, Performance는 "다운로드 + 그 이후 브라우저 처리(파싱·실행·렌더링) 전부"를 본다. Performance 안에도 Network 항목이 있어서 더 헷갈리는데, 여기 Network는 전체 타임라인의 _맥락 속_에서 본다는 점이 다르다.
  • Self Time vs Total Time: "이 함수 자체가 느린 건가(Self)?" vs "이 함수가 부르는 하위까지 합쳐서 느린 건가(Total)?"를 구분하는 용도. 최적화 대상을 잘못 잡지 않으려면 둘을 같이 봐야 한다.
  • Bottom-up vs Call Tree: 둘 다 함수 시간 분석인데 방향이 반대. Bottom-up = "가장 많이 쓴 함수가 뭐야?"(원인부터), Call Tree = "이 함수가 어디서 호출됐어?"(흐름부터).
  • Rendering vs Painting: Rendering(보라색)은 어디에 얼마나 크게 둘지 계산(Style + Layout), Painting(초록색)은 실제 픽셀을 칠하는 단계. 색이 다르고 최적화 방법도 다르다.
  • Idle이 높으면 나쁜 거 아냐?: 오히려 좋을 수 있다. CPU가 놀고 있다 = 리소스를 효율적으로 쓰고 있다는 신호일 수 있다.

실무 적용

  • 초기 로딩이 느린 페이지 진단: 🔄(Record and Reload)로 기록 → Timings에서 FCP/LCP 확인 → Summary에서 Loading 비중이 크면 리소스 최적화, Scripting이 크면 번들 크기·실행 최적화.
  • 클릭/스크롤이 버벅일 때: ●(녹화)로 해당 동작만 기록 → Frames에서 FPS 드롭 위치 확인 → Main에서 그 시점의 긴 작업(Long Task) 찾기 → Bottom-up으로 범인 함수 특정.
  • 레이아웃이 갑자기 튀는 문제: Layout Shifts 섹션에서 CLS 발생 지점 확인 → 이미지·광고·폰트에 크기 예약(width/height, aspect-ratio) 적용.
  • 애니메이션 최적화: Main에서 Layout/Paint가 반복되면 transform·opacity 기반 애니메이션으로 전환(레이아웃 안 건드림).
  • 관련 작업: [[개발자도구-Network]] · [[개발자도구-Lighthouse]] · [[Core-Web-Vitals]] · [[브라우저-렌더링-과정]]

더 공부할 것

  • Core Web Vitals (LCP / INP / CLS) 의 구체적 기준 점수와 측정 방식
  • 브라우저 렌더링 파이프라인 (Parse → Style → Layout → Paint → Composite) 전체 흐름
  • Long Tasks API 와 메인 스레드 블로킹 50ms 기준
  • requestIdleCallback / requestAnimationFrame / Web Worker 로 메인 스레드 부담 분산하기
  • Lighthouse 와 Performance 탭의 역할 차이 (자동 점수 vs 수동 정밀 분석)
  • Memory 탭 / Performance Memory 로 메모리 누수 추적하기
  • Flame Chart 읽는 법 (스택의 깊이·폭이 의미하는 것)

🔗 참고