school Are you a developer in an agency in the UK, Indonesia or India? Find out more about our free 2 day Progressive Web Apps training .

메모리 용어

이 섹션에서는 메모리 분석에 흔히 사용되는 일반적인 용어를 설명합니다. 이러한 용어는 여러 언어의 다양한 메모리 프로파일링 도구에 적용할 수 있습니다.

여기에 설명된 여러 가지 용어와 개념은 Chrome DevTools 힙 프로파일러에 대한 내용입니다. 자바, .NET 또는 기타 메모리 프로파일러를 다뤄본 경험이 있다면 다시 돌아보는 기회로 삼을 수 있습니다.

객체 크기

메모리를 일종의 기본 유형(예: 숫자와 문자열)과 객체(연관 배열)로 이루어진 그래프라고 생각하세요. 이것을 시각적으로 표현하면 아래와 같이 여러 개의 상호 연결된 점으로 이루어진 그래프 형태로 나타날 수 있습니다.

메모리의 시각적 표현

객체는 다음 두 가지 방식으로 메모리를 보유할 수 있습니다.

  • 객체 자체가 직접 보유합니다.

  • 암시적으로 다른 객체에 대한 참조를 보유함으로써 해당 객체가 가비지 수집기(줄여서 GC)에 의해 자동으로 폐기되지 않도록 합니다.

DevTools에서 힙 프로파일러를 다룰 때에는('Profiles' 아래에 있는 메모리 문제 조사용 도구) 몇 가지 정보가 담긴 열로 이루어진 형태를 접할 가능성이 높습니다. 그중 가장 눈에 띄는 두 가지는 Shallow SizeRetained Size이지만, 이들이 의미하는 바는 무엇일까요?

Shallow 및 Retained Size

Shallow size

객체 자체가 보유한 메모리 크기입니다.

일반적인 자바스크립트 객체에는 설명 내용을 담고 즉시 값을 저장하기 위한 약간의 메모리가 있습니다. 대개 배열과 문자열만 상당히 큰 Shallow Size를 가질 수 있습니다. 다만 문자열과 외부 배열의 경우 렌더러 메모리에 자체 기본 저장소가 있으며 자바스크립트 힙에는 작은 래퍼 객체만 노출됩니다.

렌더러 메모리는 검사한 페이지가 렌더링되는 프로세스의 모든 메모리이며, 기본 메모리 + 페이지의 JS 힙 메모리 + 페이지가 시작한 전담 작업자 모두의 JS 힙 메모리가 이에 해당됩니다. 그럼에도 불구하고 작은 객체도 간접적으로, 즉 다른 객체가 자동 가비지 수집 프로세스에 의해 폐기되지 않도록 차단하는 방식으로 대량의 메모리를 보유할 수 있습니다.

Retained size

객체 자체가 삭제되고, 그와 함께 GC roots에서 연결할 수 없게 된 종속 객체도 모두 삭제되면 확보되는 메모리 크기입니다.

GC roots는 네이티브 코드로부터 V8 외부의 자바스크립트 객체로 참조를 만들 때 생성되는 (지역 또는 전역) 핸들로 구성됩니다. 이러한 핸들은 모두 GC roots > Handle scopeGC roots > Global handles 아래의 힙 스냅샷 내에서 찾을 수 있습니다. 이 문서에서 브라우저 구현에 대해 자세하게 다루지 않으면서 핸들에 대해 설명하면 조금 혼란스러울 수 있습니다. GC 루트와 핸들은 둘 다 개발자가 별로 신경을 쓰지 않아도 되는 부분입니다.

많은 내부 GC가 있고 대부분은 사용자가 별 관심을 기울이지 않습니다. 애플리케이션 관점에서 보면 크게 다음과 같은 종류의 루트가 있습니다.

  • Windows 전역 객체(각 iframe에서). 힙 스냅샷에는 거리 필드가 있는데, 이는 창에서 최단 거리의 보존 경로에 있는 속성 참조의 수를 의미합니다.

  • 문서를 탐색하여 도달할 수 있는 모든 네이티브 DOM 노드로 구성된 문서 DOM 트리. 일부는 JS 래퍼가 없을 수도 있지만 래퍼가 있으면 문서가 활성화된 동안 래퍼가 활성화됩니다.

  • 경우에 따라 디버거 컨텍스트 및 DevTools 콘솔이 객체를 보존할 수도 있습니다(예: 콘솔 평가 후). 콘솔을 비우고 디버거 내 활성 중단점이 없는 상태로 힙 스냅샷을 생성합니다.

메모리 그래프는 루트로 시작하며, 브라우저의 window 객체일 수도 있고 Node.js 모듈의 Global 객체일 수도 있습니다. 이 루트 객체의 가비지 수집(GC) 방법은 개발자가 통제할 수 없습니다.

루트 객체는 통제할 수 없음

루트에서 연결할 수 없는 것은 무엇이든 가비지 수집(GC)됩니다.

참고: Shallow Size 및 Retained Size 열은 모두 데이터를 바이트 단위로 나타냅니다.

객체 보존 트리

힙은 상호 연결된 객체의 네트워크입니다. 수학에서는 이 구조를 그래프 또는 메모리 그래프라고 부릅니다. 그래프는 에지로 연결된 노드로 구성되며, 모두 레이블이 지정됩니다.

  • 노드(또는 객체)에는 이를 빌드하는 데 사용된 생성자 함수의 이름을 사용하여 레이블이 지정됩니다.
  • 에지속성의 이름을 사용하여 레이블이 지정됩니다.

힙 프로파일러를 사용하여 프로필을 기록하는 방법을 알아보세요. 아래의 힙 프로파일러 기록에서 특히 눈에 띄는 몇 가지 중에서 거리가 포함됩니다. 이 거리는 GC 루트로부터의 거리입니다. 동일한 유형의 객체 중 거의 모두가 동일한 거리에 있고 몇 개만 좀 더 먼 거리에 있다면 조사할 가치가 있는 문제입니다.

루트로부터의 거리

도미네이터

도미네이터 객체는 각 객체가 정확히 한 개의 도미네이터를 갖기 때문에 트리 구조로 구성됩니다. 객체의 도미네이터에는 자신이 지배하는 객체에 대한 참조가 없을 수도 있습니다. 즉, 도미네이터의 트리는 그래프의 스패닝 트리가 아닙니다.

아래 다이어그램에서:

  • 노드 1은 노드 2를 지배합니다.
  • 노드 2는 노드 3, 4 및 6을 지배합니다.
  • 노드 3은 노드 5를 지배합니다.
  • 노드 5는 노드 8을 지배합니다.
  • 노드 6은 노드 7을 지배합니다.

도미네이터 트리 구조

아래 예시에서 노드 #3#10을 지배하지만, #7도 GC에서 #10로의 모든 단순 경로에 존재합니다. 따라서 루트로부터 객체 A로 이어지는 모든 단순 경로에 객체 B가 존재하면 객체 B는 객체 A의 도미네이터입니다.

애니메이션 방식의 도미네이터 설명

V8 사양

메모리를 프로파일링할 때 힙 스냅샷의 형태가 왜 그런 모양을 띠는지 이유를 파악하면 요긴합니다. 이 섹션에서는 특히 V8 자바스크립트 가상 머신(V8 VM 또는 VM)에 해당하는 일부 메모리 관련 주제를 설명합니다.

자바스크립트 객체 표현

세 가지의 기본 유형이 있습니다.

  • 숫자(예: 3.14159..)
  • 부울(true 또는 false)
  • 문자열(예: 'Werner Heisenberg')

이들은 다른 값을 참조할 수 없으며 항상 리프 또는 말단 노드입니다.

숫자는 다음 중 하나로 저장할 수 있습니다.

  • 정수(Small)(SMI)라고 하는 즉치 31비트 정수값, 또는
  • 힙 숫자라고 불리는 힙 객체. 힙 숫자는 double 등과 같은 SMI 형식에 맞지 않는 값을 저장하거나 속성 설정 등 값을 박싱해야 하는 경우에 사용합니다.

문자열은 다음 중 하나에 저장할 수 있습니다.

  • VM 힙, 또는
  • 외부 렌더러의 메모리. 래퍼 객체가 생성되고 외부 저장소에 액세스하는 데 사용됩니다. 예를 들어 웹에서 수신된 스크립트 소스와 기타 콘텐츠는 VM 힙으로 복사되지 않고 여기에 저장됩니다.

새 자바스크립트 객체의 메모리는 전용 자바스크립트 힙(또는 VM 힙)에서 할당됩니다. 이러한 객체는 V8의 가비지 수집기가 관리하며, 따라서 이에 대한 강력한 참조가 최소 하나만 있어도 계속 살아있게 됩니다.

네이티브 객체는 자바스크립트 힙에 없는 다른 모든 것을 의미합니다. 네이티브 객체는 힙 객체와는 달리 수명이 다할 때까지 계속 V8 가비지 수집기가 관리하며 자바스크립트에서 자체 자바스크립트 래퍼 객체를 사용해서만 액세스할 수 있습니다.

Cons 문자열은 저장된 다음 조인되는 문자열 쌍으로 구성된 객체로, 연결(concatenation)의 결과입니다. cons 문자열 콘텐츠의 조인은 필요한 경우에만 발생합니다. 한 예로, 조인된 문자열의 하위 문자열을 생성해야 하는 경우가 있습니다.

예를 들어 ab를 연결하면 그 연결의 결과를 나타내는 문자열 (a, b)를 얻게 됩니다. 나중에 이 결과를 d와 연결하면 또 다른 cons 문자열((a, b), d)을 얻게 됩니다.

배열 - 배열은 숫자 키가 포함된 객체입니다. 배열은 주로 V8 VM에서 대량의 데이터를 저장하는 용도로 사용됩니다. 키-값 쌍 집합을 사용하는 사전과 같은 경우에 배열을 사용합니다.

일반적인 자바스크립트 객체는 저장용으로 사용되는 다음의 두 가지 배열 유형 중 하나일 수 있습니다.

  • 이름이 지정된 속성 및
  • 숫자 요소

속성의 수가 극히 적은 경우에는 자바스크립트 객체 자체 내부에 저장할 수 있습니다.

- 객체의 종류와 그 레이아웃을 설명하는 객체입니다. 예를 들어, 빠른 속성 액세스를 위한 암시적 객체 계층 구조를 설명하는 데 맵이 사용됩니다.

객체 그룹

각 네이티브 객체 그룹은 서로에 대한 상호 참조를 보유한 객체들로 구성됩니다. 예를 들어, 모든 노드에 자신의 부모 노드에 대한 링크와 다음 자식 노드 및 다음 형제 노드에 대한 링크가 있어서 연결된 그래프를 형성하는 DOM 하위 트리를 가정해 봅시다. 네이티브 객체는 자바스크립트 힙에 나타나지 않는다는 점에 유의하세요. 따라서 크기가 0입니다. 그 대신에 래퍼 객체가 생성됩니다.

각 래퍼 객체는 명령을 리디렉션하기 위해 해당 네이티브 객체에 대한 참조를 보유합니다. 또한 객체 그룹은 래퍼 객체를 보유합니다. 하지만 그렇다고 해서 수집할 수 없는 사이클이 생성되는 것은 아닙니다. GC는 래퍼가 더 이상 참조되지 않는 객체 그룹을 해제할 만큼 충분히 스마트하기 때문입니다. 하지만 단일 래퍼를 해제하는 것을 잊으면 전체 그룹 및 연관된 래퍼를 모두 보유하게 됩니다.