CS/Browser

크롬은 왜 RAM을 많이 먹을까? — 프로세스, 스레드 그리고 JavaScript

sangchu 2026. 5. 24. 22:15

들어가며

크롬에서 탭을 여러 개 열어두면 컴퓨터가 느려진다는 걸 한 번쯤 느껴봤을 것이다.

실제 맥 활성 상태 보기를 열어보면 크롬 관련 프로세스가 수십 개씩 떠 있고, RAM을 수백 MB씩 잡아먹고 있는 걸 볼 수 있다. 왜 탭 몇 개 열었을 뿐인데 이렇게 될까?

이 질문에 답하려면 먼저 "메모리"가 무엇인지부터 짚어야 한다. 우리가 일상적으로 '메모리를 많이 먹는다'고 할 때의 메모리는 RAM을 가리킨다.

프로그램은 평소엔 SSD나 HDD에 저장돼 있지만, 실행되는 순간 운영체제가 필요한 코드와 데이터를 RAM으로 복사해 올린다. CPU는 RAM에 올라온 내용을 읽으며 명령을 수행한다. 크롬도 마찬가지다.

 

그렇다면 크롬은 왜 이렇게 RAM을 많이 쓰는 걸까?

그 이유는 크롬이 웹 페이지를 여러 프로세스로 분리해 실행하기 때문이다. 프로세스마다 별도의 메모리 공간을 사용하므로, 탭과 사이트가 많아질수록 RAM 사용량도 함께 증가한다.

이제 이 질문을 따라가다 보면 자연스럽게 렌더러 프로세스, 프로세스와 스레드의 차이, 그리고 JS가 싱글스레드인 이유까지 연결된다.

 

크롬의 프로세스

크롬은 내부적으로 여러 프로세스를 띄운다. 이를 멀티프로세스 아키텍처라고 한다.

여기서 프로세스란 운영체제가 관리하는 독립적인 실행 단위다. 각 프로세스는 자기만의 메모리 공간을 가지며, 다른 프로세스의 메모리에는 직접 접근할 수 없다.

 

크롬의 프로세스는 크게 두 종류로 나뉜다.

브라우저 메인 프로세스

  • 주소창, 북마크, 탭 UI, 네트워크 관리 등 크롬 전체를 총괄하는 프로세스. 하나만 존재한다.

렌더러 프로세스

  • 웹 페이지를 렌더링하는 프로세스다.
  • 일반적으로 탭마다 하나 이상의 렌더러 프로세스가 생성된다. 다만 최근 크롬은 사이트 격리(Site Isolation) 정책을 적용하고 있어, 하나의 탭에서도 여러 렌더러 프로세스가 생성될 수 있다. 예를 들어 naver.com 페이지 안에 YouTube iframe이나 Google 로그인 iframe이 포함되어 있다면 별도의 렌더러 프로세스가 생성될 수 있다.
  • DOM 트리, CSSOM, JS 힙 등이 이 프로세스의 메모리 공간에 올라간다.
 
 

왜 탭마다 프로세스를 분리했을까?

  • 안정성
    • 탭 하나가 크래시 나도 다른 탭은 살아있다. "이 탭이 응답하지 않습니다"가 뜰 때 해당 탭만 종료할 수 있는 것이 바로 이 덕분이다.
    • 크롬 이전의 브라우저들은 탭이 하나의 프로세스를 공유했다. 그래서 탭 하나가 죽으면 브라우저 전체가 죽었다. 크롬은 탭마다 별도 프로세스를 만들어서 이 문제를 해결했다.
  • 보안
    • 프로세스가 분리되면 OS 레벨에서 메모리 접근이 차단된다.
    • 프로세스가 분리되면 브라우저는 각 페이지를 격리된 환경(Sandbox)에서 실행할 수 있다. 여기에 동일 출처 정책(Same Origin Policy)과 사이트 격리(Site Isolation)가 더해져 다른 사이트의 데이터에 접근하지 못하도록 보호한다.

 

그래서 크롬이 RAM을 많이 먹는 이유

이제 처음 질문으로 돌아오면 답이 명확해진다.

크롬 탭이 늘어날수록 렌더러 프로세스 수도 함께 증가한다.

각 프로세스마다 DOM, CSSOM, JS 실행 환경(V8 힙) 등이 별도로 메모리를 사용하므로 RAM 사용량이 크게 증가한다.

 

안정성과 보안을 위해 프로세스를 분리한 설계의 트레이드오프다.
(요즘은 크롬이 탭을 오래 보지 않으면 프로세스를 절전 상태로 전환해 RAM을 줄이는 최적화도 한다고 한다.)

 

맥 활성 상태 보기에서 직접 확인할 수 있다.

 

Google Chrome Helper (Renderer)는 웹 페이지 렌더링을 담당하는 렌더러 프로세스다. 이들은 PID(프로세스 ID)가 전부 다르다. Google Chrome이 하나만 보이는데, 이것이 주소창·북마크·탭 UI를 관리하는 메인 프로세스다.

활성 상태 보기에서 보이는 것
├── Google Chrome (PID: 58132) ← 브라우저 메인 프로세스 (스레드 52개)
├── Google Chrome Helper (Renderer) ← 탭 1 렌더러 프로세스 (560.8MB)
├── Google Chrome Helper (Renderer) ← 탭 2 렌더러 프로세스 (513.0MB)
├── Google Chrome Helper (Renderer) ← 탭 3 렌더러 프로세스 (509.6MB)
└── ... (탭 수만큼 계속)

 

Google Chrome(메인 프로세스)를 자세히 보면 다음과 같은 정보를 알 수 있다.

 

그런데 여기서 한 가지 더 눈에 띄는 것이 있다. 메인 프로세스 하나 안에 스레드가 여러 개 돌아가고 있다는 점이다.

프로세스와 스레드는 어떻게 다른 걸까?

 

프로세스 vs 스레드

  • 프로세스: OS가 관리하는 독립적인 실행 단위다. 각 프로세스는 자신만의 메모리 공간(RAM)을 할당받으며, 다른 프로세스의 메모리에 직접 접근할 수 없다.
  • 스레드: 프로세스에 할당된 메모리 안에서 여러 작업을 동시에 처리하는 단위다.

건물로 비유하면 이렇다.

  • 프로세스 = 건물. 완전히 독립된 공간. 각자 자기 땅(메모리)을 가짐. 옆 건물에 함부로 못 들어감.
  • 스레드 = 건물 안의 직원. 같은 건물(메모리)을 공유하며 일함. 여러 명이 동시에 작업 가능.
  • 싱글스레드 = 직원이 1명. 한 번에 한 가지 일만 할 수 있음.

크롬은 탭마다 프로세스를 분리하고, 각 프로세스 안에서는 여러 스레드가 돌아간다.

즉, 하나의 프로세스(건물) 안에서도 여러 스레드(직원)가 동시에 서로 다른 일을 수행할 수 있다.

 

 

JS는 싱글스레드(메인스레드)에서 실행된다

렌더러 프로세스 안에서는 메인 스레드가 JavaScript 실행뿐 아니라 DOM 생성, 스타일 계산, 레이아웃 계산 등 주요 렌더링 작업을 담당한다.

 

왜 이렇게 설계했을까?

  • 만약 JS가 멀티스레드였다면, 스레드 A와 스레드 B가 동시에 같은 DOM 노드를 건드리는 상황이 생긴다.
  • style.color = 'red'와 style.color = 'blue'가 동시에 실행되면 최종값이 무엇인지 알 수 없다.
  • JavaScript는 브라우저의 DOM을 단순하고 예측 가능하게 다루기 위해 기본적으로 단일 실행 흐름(싱글스레드) 모델을 채택했다. 이 덕분에 여러 스레드가 동시에 DOM을 수정하며 발생할 수 있는 동시성 문제도 피할 수 있다.

다만, 렌더러 프로세스 자체는 멀티스레드다.

  • 메인스레드 외에도 컴포지터 스레드, 네트워크 스레드, 워커 스레드 등이 형제처럼 나란히 존재한다.
  • "JavaScript는 싱글스레드"라는 말은 일반적인 웹 애플리케이션 코드와 DOM 조작이 하나의 메인스레드에서 실행된다는 뜻이다. (다만 Web Worker를 사용하면 별도의 스레드에서도 JavaScript를 실행할 수 있다.)
렌더러 프로세스
├── 메인스레드 ← JS 실행, DOM 생성, Style 계산, Layout 계산
├── 컴포지터스레드 ← 레이어 합성, 스크롤 처리
├── 네트워크스레드 ← 요청/응답 처리
└── 워커스레드 ← 무거운 JS 연산 (DOM 접근 불가)

 

그 외 스레드들의 역할

네트워크 스레드

  • 메인스레드가 fetch()를 호출하면 브라우저의 네트워크 계층이 요청 처리를 담당한다. 응답이 도착하면 Promise의 후속 작업(.then, await 이후 코드)이 큐에 등록되고, 이벤트 루프에 의해 다시 메인스레드에서 실행된다. 자세한 흐름은 다음과 같다.
    • 메인스레드: fetch() 호출 → 네트워크 스레드에 위임하고 메인스레드는 다음 코드 실행 → 네트워크 스레드가 서버랑 통신 (메인스레드와 독립적으로) → 응답 완료되면 .then 콜백을 마이크로태스크 큐에 등록 → 이벤트 루프가 콜스택 비어있는 거 확인 → 큐에서 콜백 꺼내서 메인스레드에서 실행

컴포지터 스레드

  • 스크롤, CSS transform, opacity 같은 작업을 처리한다. 일부 스크롤 및 애니메이션 작업을 메인스레드와 분리해 처리할 수 있어, 특정 상황에서는 더 부드러운 사용자 경험을 제공한다.
  • 브라우저 렌더링 과정에서 앞 단계(HTML 파싱 ~ Paint)는 메인스레드가 처리하고, 마지막 Composite(합성) 단계에서 컴포지터 스레드가 넘겨받는다.

워커 스레드(Web Worker)

  • 개발자가 직접 생성해서 쓰는 스레드다. 이미지 처리, 암호화, 대용량 데이터 연산처럼 무거운 JS 연산을 메인스레드 밖으로 빼낼 때 사용한다. 단, DOM에는 접근할 수 없다.

 

마치며

처음 질문으로 돌아가 보자.

 

크롬이 RAM을 많이 사용하는 이유는 단순히 탭 화면을 여러 개 띄워서가 아니다. 크롬은 안정성과 보안을 위해 웹 페이지를 여러 렌더러 프로세스로 분리해 실행한다. 그리고 각 렌더러 프로세스는 자신만의 DOM, CSSOM, JS 힙 등 독립적인 메모리 공간을 유지한다.

그 결과 탭과 사이트가 늘어날수록 프로세스 수가 증가하고, 그에 따라 RAM 사용량도 함께 증가한다. 이것이 크롬이 다른 프로그램보다 메모리를 많이 사용하는 가장 큰 이유다.

 

그리고 이 질문을 따라가다 보니 자연스럽게 프로세스와 스레드의 차이, 렌더러 프로세스 내부 구조, JavaScript가 싱글스레드로 동작하는 이유까지 연결해서 이해할 수 있었다.