>  기사  >  웹 프론트엔드  >  Chrome 개발자 도구의 JavaScript 메모리 분석에 대한 그래픽 소개

Chrome 개발자 도구의 JavaScript 메모리 분석에 대한 그래픽 소개

黄舟
黄舟원래의
2017-03-14 15:28:102150검색

메모리 누수는 컴퓨터의 사용 가능한 메모리가 점차적으로 감소하는 현상입니다. 프로그램이 사용하는 임시 메모리를 지속적으로 해제하지 못할 때 발생합니다. JavaScript 웹 애플리케이션은 누출 및 오버플로와 같은 기본 애플리케이션에서 발생하는 메모리 관련 문제에 자주 직면합니다. 웹 애플리케이션도 가비지 수집 일시 중지를 처리해야 합니다. .

JavaScript는 자동 메모리 관리를 위해 가비지 수집을 사용하지만 효과적인 메모리 관리는 여전히 중요합니다. 이 기사에서는 JavaScript 웹 애플리케이션의 메모리 문제 분석에 대해 설명합니다. 기능에 대해 배우면서 이러한 도구가 실제로 어떻게 작동하는지에 대한 이해를 높이기 위해 예제를 시험해 보시기 바랍니다. 이 기사에 사용된 용어에 익숙해지려면 메모리 101 페이지를 읽어보세요. 참고: 우리가 사용할 일부 기능은 현재 브라우저의 Chrome Canary 버전에서만 사용할 수 있습니다. 애플리케이션의 메모리 문제를 분석하기 위한 최상의 도구를 얻으려면 이 버전을 사용하는 것이 좋습니다.

생각해봐야 할 질문

일반적으로 메모리 누수 문제가 발생했다고 생각되면 다음 세 가지 질문에 대해 생각해야 합니다.

  • 내 페이지가 메모리를 너무 많이 차지하나요? - 시간라인 메모리 보기 도구(타임라인 메모리 보기)와 Chrome 작업 관리자(Chrome 작업 관리자)를 사용하면 더 많은 메모리를 사용했는지 확인할 수 있습니다. . 메모리 뷰는 페이지 렌더링 중 DOM 노드 개수, document의 문서 개수 및 JS 이벤트 청취 횟수를 추적할 수 있습니다. 경험상 더 이상 필요하지 않은 DOM 요소에 대한 참조를 피하고, 불필요한 이벤트 리스너를 제거하고, 사용하지 않을 대용량 데이터를 저장할 때는 주의하세요.

  • 내 페이지에 메모리 누수가 있나요? - 객체할당 추적(객체 모두 위치 추적기)는 JS 개체 할당을 실시간으로 확인하여 누수 위치를 찾는 데 도움이 됩니다. 또한 힙 분석기(Heap Profiler)를 사용하여 JS 힙 스냅샷을 생성하고 메모리 맵을 분석하고 스냅샷 간의 차이점을 비교하여 가비지 수집으로 정리되지 않은 개체를 찾을 수 있습니다.

  • 내 페이지는 얼마나 자주 가비지 수집되나요? - 페이지가 자주 가비지 수집되는 경우 페이지가 너무 자주 할당될 수 있습니다. 타임라인 메모리 보기는 관심 있는 일시 중지를 찾는 데 도움이 됩니다.

용어 및 기본 개념

이 섹션은 기억 분석에 소개되어 있습니다. 다른 언어의 메모리 분석 도구에 사용되는 일반적인 용어입니다. 여기에 나온 용어와 개념은 힙 프로파일러 UI 도구 및 관련 문서에서 사용됩니다.

이는 메모리 분석 도구를 효과적으로 사용하는 방법에 익숙해지는 데 도움이 됩니다. Java, .NET 등의 언어에 대한 메모리 분석 도구를 사용해 본 적이 있다면 리뷰가 될 것입니다.

객체 크기

메모리를 기본 유형(예: 숫자 및 문자열)과 객체(연관 배열) 차트의 모음으로 생각하세요. 일련의 관련 사항을 나타내는 다음 다이어그램과 유사할 수 있습니다.

객체에는 메모리를 사용하는 두 가지 방법이 있습니다.

  • 객체 자체가 메모리를 직접 사용합니다.

  • 다른 개체에 대한 참조를 암시적으로 유지합니다. 이 방법을 사용하면 가비지 수집(GC)이 해당 개체를 자동으로 재활용하는 것을 방지할 수 있습니다.

DevTools의 힙 프로파일러(DevTools의 "Profile" 탭에 있는 메모리 문제를 분석하는 데 사용되는 도구인 힙 프로파일러)를 사용하면 다음과 같은 열을 발견하고 놀랄 수 있습니다. 다양한 정보를 표시합니다. 그 중 두 가지는 직접 메모리 점유(얕은 크기) 총 메모리 점유(보유 크기) 입니다.

직접 메모리 점유(Shallow Size, 참조 객체가 점유하는 메모리 제외)

객체 자체가 점유하는 메모리입니다.

일반적인 JavaScript 개체에는 개체를 설명하고 개체의 직접 값을 저장하기 위해 예약된 메모리가 있습니다. 일반적으로 배열과 문자열만 메모리를 직접적으로 많이 차지합니다(얕은 크기). 그러나 문자열과 배열은 종종 기본 데이터 부분을 렌더러 메모리에 저장하고 JavaScript 개체 스택에 작은 래퍼 개체만 노출합니다.

렌더러 메모리는 분석하는 페이지의 렌더링 프로세스에 사용되는 모든 메모리를 말합니다. 페이지 자체의 메모리 + 페이지의 JS 힙에서 사용되는 메모리 + 트리거된 관련 작업자 프로세스(작업자) 페이지별 JS 힙에서 사용되는 메모리입니다. 그러나 작은 객체는 쓰레기에 의해 자동으로 다른 객체가 수집되는 것을 방지함으로써 간접적으로 많은 양의 메모리를 차지할 수 있습니다.

점유된 총 메모리(보유된 크기, 참조된 객체가 점유한 메모리 포함)

객체가 삭제되면 객체가 참조하는 종속 객체는 GC가 될 수 없습니다. 루트(GC 루트)는 이를 참조하며, 개체가 차지하는 전체 메모리에는 이러한 종속 개체가 차지하는 메모리가 포함됩니다.

GC 루트컨트롤러(handles)로 구성됩니다(로컬 또는 글로벌). V8 엔진 외부의 JavaScript 객체에 대한 참조가 내장함수(네이티브 코드)에 의해 설정될 때 생성됩니다. 이러한 컨트롤러는 모두 힙 스냅샷의 GC 루트(GC 루트) > 핸들 범위GC 루트 >전역 핸들러 에서 찾았습니다. 이 기사에서 이러한 컨트롤러를 소개하는 것은 브라우저 구현에 대한 깊은 이해가 없으면 혼란스러울 수 있습니다. GC 루트와 컨트롤러에 대해 너무 걱정할 필요가 없습니다.

사용자에게 중요하지 않은 내부 GC 루트가 많이 있습니다. 애플리케이션 관점에서 보면 다음과 같은 상황이 있습니다.

참고: 힙 스냅샷을 생성할 때 사용자가 콘솔에서 코드를 실행하거나 디버깅 중단점을 활성화하지 않는 것이 좋습니다.

메모리 맵은 브라우저의

객체 또는 windowNode.js 모듈 객체일 수 있는 루트로 시작합니다. 이러한 개체를 메모리에서 회수하는 방법은 사용자가 제어할 수 없습니다. Global

GC 루트로 탐색할 수 없는 객체는 메모리를 재활용합니다.

참고: 직접 점유된 메모리 필드와 총 메모리 점유 필드의 데이터는 바이트 단위로 표시됩니다.

객체가 차지하는 전체 메모리 트리

우리는 이전에 힙이 상호 관련된 다양한 객체로 구성된 네트워크 구조임을 배웠습니다. 디지털 세계에서는 이러한 구조를

그래프 또는 메모리 그래프라고 부른다. 그래프는 에지로 연결된 노드로 구성되며 모두 레이블이 지정됩니다.

  • 노드 ( 또는 Object) 노드의 태그 이름은 생성자에 의해 결정됩니다. 함수 이름 결정됩니다

  • Edges 레이블 이름은 속성

의 이름입니다. 이 문서에서는 힙 분석기를 사용하여 스냅샷을 생성하는 방법을 배웁니다. 아래 그림의 힙 분석기에 의해 생성된 스냅샷에서 거리 필드를 볼 수 있습니다. 거리 필드는 객체에서 GC 루트까지의 거리를 나타냅니다. 동일한 유형의 모든 객체가 동일한 거리에 있지만 작은 하위 집합이 더 멀리 떨어져 있는 경우 조사해야 할 문제가 있을 수 있습니다.

도미네이터

도미네이터는 각 개체에 도미네이터가 있으므로 트리 구조와 같습니다. 객체의 컨트롤러는 자신이 지배하는 객체를 직접 참조할 수 없습니다. 즉, 지배 객체 트리 구조는 그래프의 스패닝 트리가 아닙니다.

위 그림에서:

  • 노드 1이 노드 2를 지배합니다

  • 노드 2가 노드 3, 4, 6을 지배

  • 노드 3이 노드 5를 지배

  • 노드 5가 노드 8을 지배

  • 노드 6이 노드 7을 지배합니다

아래 예에서 노드 #3#10의 지배적인 플레이어이지만 #7은 모든 노드에서 지배적인 노드이기도 합니다. #10에 대한 GC가 경로에 나타납니다. 이와 같이 루트 노드에서 A 객체까지의 모든 경로에 B 객체가 나타나면 B 객체가 A 객체의 지배적 객체가 됩니다.

V8 소개

이 섹션에서는 V8 JavaScript 가상 머신 (V8 VM 또는 VM) 관련. 메모리를 분석할 때 힙 스냅샷을 이해하려면 이러한 개념을 이해하는 것이 도움이 됩니다.

JavaScript 개체 설명

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

다른 값을 참조하지 않으며 리프 노드 또는 터미널 노드만 됩니다.

숫자는 다음 두 가지 방법 중 하나로 저장됩니다.

  • 31비트

    정수직접 값, 호출: 작은 정수(작은 정수s)(SMI) 또는

  • 힙 개체,

    힙 값으로 참조됨 . 힙 값은 double과 같이 SMI 저장에 적합하지 않은 데이터를 저장하거나 이 값과 같이 값을 boxing해야 하는 경우에 사용되며, 속성 값.

문자 데이터는

  • VM 힙 두 가지 방식으로 저장됩니다. 또는 외부 렌더러 메모리

  • . 이때 VM 힙에 직접 복사되는 대신 웹 페이지 패키지에 저장된 스크립트 리소스, 기타 콘텐츠 등 저장 위치에 액세스하기 위해 래퍼 개체가 생성됩니다.

새로 생성된 JavaScript 개체에는 JavaScript 힙(또는

VM 힙)에 메모리가 할당됩니다. 이러한 객체는 V8의 가비지 수집기에 의해 관리되며 이에 대한 강력한 참조가 있는 한 메모리에 유지됩니다.

로컬 객체는 모두 JavaScript 힙에 없는 객체입니다. 힙 객체와 달리 라이프사이클 동안 V8에 의해 가비지 수집되지 않습니다. JavaScript를 통해 객체 참조를 래핑합니다.

연결 문자열 은 한 쌍의 문자열로 병합된 개체이며 병합의 결과입니다. 연결 문자열은 필요한 경우에만 병합됩니다. 연결된 문자열과 마찬가지로 부분 문자열을 구성해야 합니다.

예를 들어

ab를 연결하면 연결 결과를 나타내는 데 사용되는 문자열 (a, b)를 얻습니다. 나중에 이 결과를 d와 연결하면 또 다른 연결된 문자열((a, b), d)을 얻게 됩니다.

배열(배열s) - 배열은 숫자 키가 있는 개체입니다. V8 엔진에서 대용량 데이터를 저장할 때 널리 사용됩니다. 사전과 같은 키-값 쌍이 있는 객체는 배열을 사용하여 구현됩니다.

일반적인 JavaScript 객체는 두 가지 배열 유형, 즉

  • 명명된 속성과

  • 숫자 요소 중 하나에 저장될 수 있습니다.

속성이 몇 개만 있는 경우 해당 속성은 JavaScript 개체 자체에 직접 저장됩니다.

지도 - 개체 유형과 해당 구조를 설명하는 데 사용되는 개체입니다. 예를 들어, 맵은 객체 속성

객체 그룹

에 빠르게 액세스할 수 있도록 객체의 구조를 설명하는 데 사용됩니다. 각 로컬 객체 그룹은 상호 연관된 객체 세트로 구성됩니다. 예를 들어 DOM 하위 트리에서 각 노드는 연관 그래프를 형성하는 상위 요소, 다음 하위 요소 및 다음 형제 요소에 액세스할 수 있습니다. 기본 요소는 JavaScript 힙에 표시되지 않습니다. 따라서 래핑 개체가 생성되는 동안 크기가 0이 됩니다.

각 래퍼 개체에는 이러한 로컬 개체에 대한 작업을 전달하는 데 사용되는 로컬 개체에 대한 참조가 있습니다. 이러한 로컬 개체에는 래핑된 개체에 대한 참조도 있습니다. 그러나 이는 복구할 수 없는 루프를 생성하지 않습니다. GC는 더 이상 래핑된 개체에 대한 참조가 없는 로컬 개체를 식별하고 해제할 만큼 똑똑합니다. 그러나 래퍼 개체가 해제되지 않으면 모든 개체 그룹 및 관련 래퍼 개체가 유지됩니다.

전제 조건 및 유용한 팁

Chrome 작업 관리자

참고: 메모리 프로파일링을 위해 Chrome을 사용할 때는 깔끔한 테스트 환경을 설정하는 것이 가장 좋습니다.

Chrome의 메모리 관리자를 열고, 메모리 필드를 관찰하고, 페이지에서 관련 작업을 수행하면 이 작업으로 인해 페이지가 많은 메모리를 차지하게 되는지 빠르게 확인할 수 있습니다. Chrome 메뉴 > 도구에서 또는 Shift + Esc를 눌러 메모리 관리자를 찾을 수 있습니다.

열고 헤더를 마우스 오른쪽 버튼으로 클릭하고 JavasScript에서 사용하는 메모리 옵션을 선택합니다.

DevTools 타임라인을 통해 메모리 문제 찾기

문제 해결의 첫 번째 단계는 문제가 존재한다는 것을 증명하는 것입니다. 이를 위해서는 문제의 기준 척도 역할을 하는 재현 가능한 테스트를 만들어야 합니다. 재현 가능한 절차가 없으면 문제를 안정적으로 측정할 수 없습니다. 즉, 비교를 위한 기준선이 없으면 어떤 변경 사항으로 인해 문제가 발생했는지 알 수 없습니다.

타임라인 패널은 프로그램에 문제가 있을 때 발견하는 데 매우 유용합니다. 웹 애플리케이션이나 웹사이트가 로드되고 상호 작용하는 순간을 보여줍니다. 모든 이벤트: 리소스 로드부터 JavaScript 디코딩, 스타일 계산, 가비지 수집 일시 중지 및 페이지 다시 그리기까지. 모두 타임라인에 표시됩니다.

메모리 문제를 분석할 때 타임라인 패널의 메모리 보기를 사용하여 다음을 관찰할 수 있습니다.

    사용된 총 메모리 – 메모리 사용량이 증가했습니다. ?
  • DOM 노드 수
  • 문서 수(문서)
  • 등록 수 이벤트 리스너

메모리 분석 중 메모리 찾기에 대한 추가 정보 누출에 대해서는 Zack Grossbart의 Chrome DevTools를 사용한 메모리 프로파일링을 참조하세요

문제의 존재 증명

가장 먼저 해야 할 일은 문제의 원인이라고 생각되는 것이 무엇인지 찾는 것입니다. 메모리 누수에 대한 몇 가지 조치. 이는 마우스 오버, 클릭 또는 페이지 성능 저하를 일으킬 수 있는 기타 상호 작용을 포함하여 페이지에서 발생하는 모든 이벤트일 수 있습니다.

타임라인 패널(Ctrl+E 또는 Cmd+E)에서 녹화를 시작한 다음 테스트하려는 작업을 수행하세요. 가비지 수집을 강제하려면 패널에서 휴지통 아이콘(

)을 클릭하세요.

다음은 일부 포인트가 가비지 수집되지 않는 메모리 누수의 예입니다.

일부 반복 테스트 후에 들쭉날쭉한 그래픽( 메모리 패널 위)은 프로그램에 수명이 짧은 개체가 많이 있음을 나타냅니다. 그리고 일련의 작업을 수행해도 메모리가 일정 범위 내로 유지되지 않고, DOM 노드 수가 처음의 수로 돌아오지 않는다면 메모리 누수를 의심해볼 수 있습니다.

메모리 문제를 식별한 후에는

프로필 패널 프로파일러의 힙 분석기를 사용하여 문제를 찾을 수 있습니다. 문제의 근원.

예시: 타임라인을 통해 기억력 문제를 효과적으로

연습분석하는 데 도움이 되는 기억력 성장 예시를 시도해 보세요.

메모리 재활용기

메모리 수집기(V8의 것과 유사)는 어떤 개체가 라이브인지, 어떤 개체가 죽은(쓰레기)으로 간주되는 개체는 참조할 수 없습니다(unr각각가능).

가비지 컬렉션(GC)이 JavaScript 실행의 논리 오류로 인해 가비지 개체를 수집하지 못하는 경우 해당 가비지 개체는 더 이상 재활용할 수 없습니다. 이와 같은 상황은 결국 애플리케이션을 점점 더 느리게 만들 것입니다.

예를 들어 코드를 작성할 때 일부

변수와 이벤트 리스너는 더 이상 사용되지 않지만 일부 코드에서는 여전히 참조됩니다. 참조가 여전히 존재하는 한 참조된 개체는 GC에서 올바르게 재활용될 수 없습니다.

애플리케이션이 실행되는 동안 일부 DOM 개체업데이트/제거되었을 수 있습니다. DOM 개체를 참조하는 변수를 확인하고null 설정하세요. . 다른 개체(또는 다른 DOM 요소)를 참조할 수 있는 개체 속성을 확인하세요. 커질 수 있는 변수 캐시를 지켜보세요.

힙 분석기

스냅샷 찍기

프로필 패널에서 힙 스냅샷 찍기를 선택하고 시작을 클릭하거나 Cmd를 누르세요. + E 또는 Ctrl + E:

스냅샷은 처음에 렌더러 프로세스 메모리에 저장됩니다. 요청 시 DevTools로 가져오며 스냅샷 버튼을 클릭하면 볼 수 있습니다. 스냅샷이 DevTools에 로드되어 표시되면 스냅샷 제목 아래의 숫자는 도달 가능한 JavaScript 객체가 차지하는 총 메모리 양을 표시합니다.

예: 타임라인 패널에서 메모리 사용량을 모니터링하려면 action 예에서 가비지 수집을 시도해 보세요.

스냅샷 지우기

모든 스냅샷을 지우려면 지우기 모두 버튼 아이콘 ()을 클릭하세요.

참고: DevTools 창을 닫아도 수집된 스냅샷은 렌더링 메모리에서 삭제되지 않습니다. DevTools를 다시 열면 이전 스냅샷 목록이 그대로 남아 있습니다.

앞서 언급한 내용을 기억하세요. 스냅샷을 찍을 때 DevTools에서 강제로 GC를 수행할 수 있습니다. 스냅샷을 찍으면 자동으로 GC가 실행됩니다. 타임라인에서 휴지통(가비지 수집) 버튼()을 클릭하면 가비지 수집을 쉽게 수행할 수 있습니다.

예: 분산된 개체를 시도하고 힙 프로파일러로 분석합니다. (객체) 아이템의 컬렉션을 볼 수 있습니다.

스냅샷 보기 전환

스냅샷은 다양한 작업에 따라 보기를 전환할 수 있습니다. 그림의 선택 상자를 통해 전환할 수 있습니다.

다음은 세 가지 기본 보기입니다.

  • 요약 (요약) - 생성자를 통해 이름 분류로 객체 표시

  • Containment - 힙 콘텐츠를 감지하는 데 사용할 수 있습니다.

  • 도미네이터설정

    팅 패널에서 보기를 열 수 있으며, 메모리 성장 지점을 찾는 데 사용할 수 있습니다.
색상에 따라 객체 구별

객체의 속성과 속성값은 종류가 다르며 자동으로 색상으로 구분됩니다. 각 속성은 다음 네 가지 중 하나입니다.

a:property

-

이름으로 색인이 생성된 일반 속성으로 .( 점 )
    연산자
  • 또는 [](대괄호) 참조(예: ["foo bar"];

    0:element) - [](대괄호)로 참조되는 숫자 인덱스가 있는 일반 속성을 전달합니다.

  • a:context var - 함수 내 속성, 함수 컨텍스트 내 name Quote;

  • a:system prop - JavaScript VM에 의해 추가된 속성이며 JavaScript 코드로 액세스할 수 없습니다.

  • 이라는 개체에 해당하는 JavaScript 유형이 없습니다. 이는 JavaScript VM 개체 시스템에 내장되어 있습니다. V8은 대부분의 내장 객체와 사용자 JS 객체를 동일한 힙에 배치합니다. 하지만 그것들은 V8의 내부 개체일 뿐입니다.

  • 세부정보 보기

요약 보기(요약 보기)System기본적으로 요약 보기에 표시되며 총 개체 수를 표시하고 확장할 수 있는 스냅샷을 엽니다. 특정 콘텐츠 표시: 처음에는 요약 보기에서 스냅샷이 열리고 표시

개체 총계가 표시되며 확장하여 인스턴스를 표시할 수 있습니다.

첫 번째 수준은 "전체" 행이며 다음과 같이 표시됩니다.

  • 생성자(생성자) 는 모든 것을 의미합니다. 이 생성자

    에 의해 생성된
  • 객체의 인스턴스 수는 객체 Count

  • 에 표시됩니다.

    Shallow size 열에는 해당 생성자

  • 에 의해 생성된 객체의 얕은 크기(메모리를 직접 점유)의 총 개수가 표시됩니다. 해당 객체가 차지하는 최대 메모리를 나타내는 열

  • Distance객체에서 GC 루트까지의 최단 거리를 나타내는 열

전체 행을 확장하면 모든 개체 인스턴스가 표시됩니다. 각 인스턴스가 차지하는 직접 메모리와 총 메모리가 그에 따라 표시됩니다. @ 기호 뒤의 숫자는 개체의 고유 ID이며 이를 사용하면 개체별로 서로 다른 스냅샷을 비교할 수 있습니다.

예: 개요 보기 사용 방법을 알아보려면 이 예(새 탭에서 열림)를 시도해 보세요.

노란색 객체는 JavaScript에서 참조하는 반면, 빨간색 객체는 노란색 배경색의 분리된 노드에서 참조한다는 점을 기억하세요.

비교 보기

이 보기는 서로 다른 스냅샷을 비교하여 스냅샷 간의 차이점을 찾고, 메모리 누수가 있는 개체를 찾는 데 사용됩니다. 애플리케이션의 특정 작업으로 인해 누출이 발생하지 않음을 증명하려면(예: 문서를 연 다음 닫는 등의 한 쌍의 작업과 실행 취소 작업이 누출을 유발하지 않음) 다음 단계를 시도해 볼 수 있습니다.

  1. 작업 전에 힙 스냅샷을 찍습니다.

  2. 작업을 수행합니다(누출을 일으킬 것으로 생각되는 작업을 수행합니다). >

  3. 이전 작업을 취소하고(이전 작업을 되돌리고 여러 번 반복)
  4. 두 번째 스냅샷을 찍고 컨트롤 뷰로 전환합니다. 스냅샷 1로.
  5. 비교 보기에서는 두 스냅샷의 차이점이 표시됩니다. 일반 카테고리를 펼치면 추가 및 삭제된 개체가 표시됩니다.

예시: 사용 방법을 알아보려면 예시(새 탭에서 열기)를 시도해 보세요. 메모리 누수를 찾아보세요.

포함 뷰

컨트롤 뷰는 애플리케이션 객체 구조의 "조감도"라고 할 수 있습니다. 이를 통해 JavaScript 개체와 마찬가지로 VM 개체 내부의 함수 내부를 볼 수 있어 애플리케이션의 메모리 사용량에 대한 매우 낮은 수준의 보기를 제공합니다.

이 보기는 여러 진입점을 제공합니다.

  • DOMWindow 개체

    - 이러한 개체는 JavaScript 코드에 대한 "전역" 개체입니다.

  • GC 루트

    - VM 가비지 수집기의 실제 GC 루트

  • 네이티브 개체

    - 개체 찾아보기 DOM 노드, CSS 규칙과 같은 자동 작업을 수행하기 위해 JavaScript 가상 머신에 "푸시"됩니다(자세한 내용은 다음 섹션에서 소개됩니다.)

  • 다음 그림은 일반적인 컨트롤 뷰:

예: 컨트롤 뷰를 사용하여

클로저

내부를 확인하는 방법을 보려면 예제(새 탭에서 열기)를 시도해 보세요. 그리고 이벤트 처리.

클로저 팁

함수 이름을 지정하면 스냅샷에서 클로저 함수를 구별하는 데 도움이 될 수 있습니다. 예를 들어 다음 예에서는 함수 이름을 지정하지 않습니다.

function createLargeClosure() {
  var largeStr = new Array(1000000).join('x');

  var lC = function() { // this is NOT a named function
    return largeStr;
  };

  return lC;
}

다음 예에서는 함수 이름을 지정합니다.
function createLargeClosure() {
  var largeStr = new Array(1000000).join('x');

  var lC = function lC() { // this IS a named function
    return largeStr;
  };

  return lC;
}

예: Try 이 예는 메모리에서 클로저의 영향을 분석하는 데 eval이 나쁜 이유입니다. 힙 할당 로깅에 대한 다음 예제를 시도해 볼 수도 있습니다.

DOM 메모리 누수 노출

이 도구의 독특한 점은 브라우저 기본 개체(DOM 노드, CSS 규칙)와 JavaScript 개체 간의 양방향 참조를 표시한다는 것입니다. 이는 무료 DOM 하위 노드를 역참조하는 것을 잊어서 발생하는 미묘한 메모리 누수를 찾는 데 도움이 될 수 있습니다.

DOM 메모리 누수는 생각보다 더 흔할 수 있습니다. 다음 예를 살펴보십시오. #tree 객체는 언제 GC됩니까?

var select = document.querySelector;
  var treeRef = select("#tree");
  var leafRef = select("#leaf");
  var body = select("body");

  body.removeChild(treeRef);

  //#tree can't be GC yet due to treeRef
  treeRef = null;

  //#tree can't be GC yet due to indirect
  //reference from leafRef

  leafRef = null;
  //#NOW can be #tree GC

재귀적으로 #leaf를 참조하는 상위 노드(parentNode)에 대한 참조를 나타냅니다. 따라서 leafRef가 null화된 경우에만 는 전체 트리를 나타냅니다. 구조는 GC에 의해 재활용됩니다. #tree#tree

예: DOM 노드 누출을 시도하여 DOM 노드에서 메모리 누출이 발생하는 위치와 이를 찾는 방법을 알아보세요. 이 예를 볼 수도 있습니다. DOM 누출이 예상보다 큽니다.

Gonzalo Ruiz de Villa의 기사 Chrome DevTools를 사용하여 메모리 누수 찾기 및 디버깅을 확인하여 DOM 메모리 누수 및 메모리 분석의 기본 사항에 대해 자세히 알아보세요.

기본 개체는 요약 및 포함 보기에서 더 쉽게 찾을 수 있습니다. 전용 범주가 있습니다.

예: 이 예를 시도해 보세요(새 탭에서) ) DOM 트리를 분리하는 방법을 알아보세요.

Dominators 보기

Dominators 보기에는 스택 그래프의 Dominators 트리가 표시됩니다. Dominator 뷰는 Containment 뷰와 유사하지만 속성 이름이 없습니다. 이는 눈금자가 직접 참조가 없는 객체일 수 있기 때문입니다. 이는 눈금자 트리가 힙 그래프의 스패닝 트리가 아님을 의미합니다. 그러나 이는 메모리 성장 지점을 빠르게 찾는 데 도움이 되는 유용한 보기입니다.

참고: Chrome Canary에서는 DevTools의 설정 > 고급 힙 스냅샷 속성 표시에서 Dominator 보기를 켤 수 있으며 DevTools를 다시 시작한 후에 적용됩니다.

예: 이 예(새 탭에서 열기)를 사용하여 메모리 성장 포인트를 찾는 연습을 해보세요. 경로와 도미네이터를 유지하는 다음 예를 더 자세히 시도해 볼 수 있습니다.

객체 할당 추적기

객체 추적기는 힙 프로파일러의 스냅샷 증분 업데이트 분석과 타임라인 패널 기록을 통합합니다. 다른 도구와 마찬가지로 객체의 힙 구성을 기록하려면 기록을 시작하고 일련의 작업을 수행한 다음 기록을 중지하고 분석해야 합니다.

객체 추적기는 힙 스냅샷을 지속적으로 기록하고(최대 50밀리초마다!) 마지막 스냅샷을 기록합니다. 이 힙 할당 분석기는 개체가 생성된 위치와 예약된 경로를 보여줍니다.

객체 분석기 열기 및 사용

객체 분석기 사용을 시작하려면: 1. 최신 버전의 Chrome을 사용하고 있는지 확인하세요. 카나리아.

  1. DeveTools를 열고 톱니바퀴 아이콘을 클릭하세요(역자: 이 단계의 사용법을 이해할 수 없습니다).

  2. 이제 프로파일러 패널을 열면 "힙 할당 기록" 옵션이 표시됩니다.

위의 막대는 힙에서 생성된 새 객체를 나타냅니다. 높이는 해당 개체의 크기에 해당하며 해당 색상은 개체가 마지막으로 촬영된 스냅샷에 여전히 있는지 여부를 나타냅니다. 파란색 열은 해당 개체가 타임라인 끝에 여전히 있음을 나타내고 회색 열은 타임라인에서 객체가 생성되었지만 종료되기 전에 메모리가 회수되었습니다.

위의 예에서는 액션이 ​​10번 실행되었습니다. 동일한 프로그램은 5개의 개체를 유지하므로 마지막 5개의 파란색 막대가 유지됩니다. 그러나 마지막 남은 열에는 잠재적인 문제가 있습니다. 타임라인의 슬라이더를 사용하여 특정 스냅샷을 확대하고 할당된 개체를 찾을 수 있습니다.

힙에 있는 객체를 클릭하면 힙 스냅샷 하단에 예약된 총 메모리 트리가 표시됩니다. 이 개체에 대해 예약된 총 메모리 트리를 검사하면 이 개체가 수집되지 않은 이유를 이해하는 데 충분한 정보를 얻을 수 있으며 코드를 적절하게 변경하여 불필요한 참조를 제거할 수 있습니다.

메모리 분석 FAQ

Q: 개체의 모든 속성을 볼 수는 없지만 문자열이 아닌 값도 볼 수 있습니다! 왜?

모든 속성이 JavaScript 힙에 그대로 저장되는 것은 아닙니다. 그 중 일부는 네이티브 코드의 getter 메소드를 실행하여 얻습니다. 이러한 속성은 getter에 대한 호출을 방지하고 해당 getter가 "순수(Pure)" 함수가 아닌 경우 프로그램의 상태 변경을 방지하기 위해 힙 스냅샷에 캡처되지 않습니다. 마찬가지로 숫자와 같은 문자열이 아닌 값은 스냅샷 크기를 줄이기 위해 캡처되지 않습니다.

Q: @ 기호 뒤의 숫자는 무엇을 의미하나요? 주소인가요, 아니면 아이디인가요? 이 ID 값이 정말 고유한가요?

객체 ID입니다. 객체는 가비지 수집 중에 제거되므로 객체의 주소를 표시하는 것은 의미가 없습니다. 이러한 개체 ID는 실제 ID입니다. 즉, 서로 다른 스냅샷 간에 고유하게 표시됩니다. 이를 통해 힙 상태를 정확하게 비교할 수 있습니다. 이러한 ID를 유지하면 GC 프로세스에 추가 오버헤드가 추가되지만 이는 첫 번째 힙 스냅샷이 기록될 때만 할당됩니다. 힙 분석기를 사용하지 않으면 추가 오버헤드가 없습니다.

Q: "죽은"(참조되지 않은) 객체가 스냅샷에 포함됩니까?

아니요, 참조할 수 있는 개체만 스냅샷에 표시됩니다. 또한 스냅샷을 생성하기 전에 GC 작업이 자동으로 수행됩니다.

참고: 이 글을 작성할 당시에는 힙 크기가 줄어드는 것을 방지하기 위해 스냅샷을 찍을 때 더 이상 GC를 수행하지 않을 계획입니다. 이제 이런 경우가 발생하지만 가비지 개체는 여전히 스냅샷 외부에 표시됩니다.

Q: GC 루트는 무엇으로 구성되나요?

그룹화되어

  • 기본 개체 그래프

  • 기호 테이블

  • VM 스레드의 스택

  • 캐시 편집; ;

  • 전역 컨트롤러.

Q: 힙 프로파일러와 타임라인 메모리 보기를 사용하여 메모리 누수를 감지할 수 있다는 것을 배웠습니다. 그런데 어떤 도구를 먼저 사용해야 할까요?

타임라인 패널은 페이지를 처음 사용할 때 과도한 메모리 사용량을 진단하고 속도가 느려지는 것을 진단하는 데 사용됩니다. 느린 웹 사이트는 메모리 누수의 전형적인 징후이지만 다른 이유일 수도 있습니다. 렌더링이나 네트워크 병목 현상이 있을 수 있으므로 페이지의 실제 문제를 해결해야 합니다. 메모리 문제인지 확인하려면 타임라인 패널과 메모리 탭을 엽니다. 기록 버튼을 클릭하고 애플리케이션에서 메모리 누수가 발생할 수 있다고 생각되는 작업을 여러 번 반복합니다. 녹음을 중지하세요. 애플리케이션의 메모리 사용량 그래프가 생성됩니다. 메모리 사용량이 감소하지 않고 계속 증가한다면 이는 애플리케이션에 메모리 누수가 있을 수 있다는 신호입니다.

일반적으로 일반 애플리케이션의 메모리 사용량 그래프는 들쭉날쭉합니다. 메모리가 사용된 후 가비지 수집기에 의해 회수되기 때문입니다. 이 지그재그에 대해 걱정하지 마세요. JavaScript로 인해 항상 메모리 소비가 발생하며 심지어 비어 있는

이라도 이러한 지그재그를 유발할 수 있으며 이는 피할 수 없습니다. 연속적인 메모리를 많이 할당하는 형태가 아닌 이상 메모리 가비지가 많이 발생한다는 뜻이다.

requestAnimationFrame

위 사진의 성장선은 주의가 필요합니다. 메모리 태그의 DOM 노드 카운터, 문서 카운터 및 이벤트 리스너 개수도 진단 분석 중에 매우 유용합니다. DOM 노드 수는 사용되는 기본 메모리이며 JavaScript 메모리 맵에 영향을 주지 않습니다.

애플리케이션에 메모리 누수가 있음이 확인되면 힙 분석기를 사용하여 메모리 누수를 찾을 수 있습니다.

Q: 힙 스냅샷에서 일부 DOM 노드의 번호가 "분리된 DOM 트리"로 빨간색으로 표시되고 다른 노드는 노란색으로 표시되는 것을 발견했습니다. 이것은 무엇을 의미합니까?

색상이 다양하다는 것을 알 수 있습니다. 빨간색 노드(어두운 배경)는 JavaScript에서 직접 참조하지 않지만 별도의 DOM 구조의 일부이므로 메모리에 남아 있습니다. 노드가 JavaScript에 의해 참조될 수 있으며(아마도 클로저 또는 변수에서) 이 참조는 전체 DOM 트리가 회수되는 것을 방지합니다.

노란색 노드(노란색 배경)는 JavaScript를 직접 참조합니다. JavaScript 참조를 찾으려면 동일한 분리된 DOM 트리에서 노란색 노드를 찾으세요. DOM 창에서 해당 노드까지의 속성 참조 체인을 볼 수 있습니다(예:

).

다음 동적 다이어그램은 분리된 노드의 프로세스를 보여줍니다.

window.foo.bar[2].baz

: 이 예제 분리 노드를 시도하면 다음을 볼 수 있습니다. 타임라인의 노드 라이프사이클을 확인한 다음 힙 스냅샷을 찍어 분리된 노드를 찾습니다.

Q: 직접 메모리 점유(Shallow Size)와 전체 메모리 점유(Retained Size)는 각각 무엇을 나타내고, 그 차이점은 무엇인가요?

이런 경우 객체는 두 가지 방식(살아 있음)으로 메모리에 존재할 수 있습니다. 즉, 다른 액세스 가능한(살아 있는) 객체에 의해 직접 유지되거나(창 및 문서 객체는 항상 액세스 가능) 암시적으로 포함된 참조입니다. 기본 객체(DOM 객체와 같은). 후자의 방법은 객체가 GC에 의해 자동으로 재활용되는 것을 방지하여 메모리 누수를 일으킬 수 있습니다. 객체 자체가 차지하는 메모리를 직접 메모리라고 합니다. 일반적으로 배열과 문자열은 더 많은 직접 메모리(얕은 크기)를 예약합니다.

모든 크기의 개체는 다른 개체가 회수되는 것을 방지하여 큰 메모리 사용량을 보존할 수 있습니다. 객체가 삭제되면(객체가 생성한 일부 종속성을 더 이상 참조할 수 없음) 해제할 수 있는 메모리 양을 점유된 총 메모리(보유 크기)라고 합니다.

Q: 생성자 및 보유 필드 아래에 많은 데이터가 있습니다. 메모리 누수가 발생하는지 조사하려면 어디서부터 시작해야 합니까?

일반적으로 리테이너별로 정렬되는 첫 번째 개체부터 시작하는 것이 가장 좋습니다. 리테이너는 거리(창 개체까지의 거리 참조)별로 정렬됩니다.

가장 짧은 거리에 있는 객체가 선호되는 객체일 수 있으며 이로 인해 메모리 누수가 발생할 수 있습니다.

Q: 요약, 비교, 지배자 및 봉쇄 보기의 차이점은 무엇인가요?

보기를 전환하면 차이를 경험할 수 있습니다.

  • 요약 보기는 생성자별로 그룹화된 객체(및 메모리 사용량)를 찾는 데 도움이 됩니다. 이 보기는 DOM 메모리 누수를 찾는 데 유용합니다.

  • 비교 보기에서는 어떤 객체의 메모리가 올바르게 회수되었는지 표시하여 메모리 누수를 검색할 수 있습니다. 일반적으로 작업 전후에 두 개 이상의 메모리 사용량 스냅샷이 기록됩니다. 해제된 메모리와 참조 개수의 차이를 보고 메모리 누수가 있는지 확인하고 원인을 찾는다.

  • 포함(제어) 보기에는 개체 구조가 더 잘 표시되어 전역 범위(예: 창)에서 개체 참조를 분석하여 이러한 개체를 유지하는 항목을 찾는 데 도움이 됩니다. 이를 통해 클로저를 분석하고 객체를 더 깊이 드릴다운할 수 있습니다.

  • Dominators 보기를 사용하면 중복된 객체가 특정 위치(예: 참조된 객체)에 남아 있지 않은지 확인하고 삭제/휴지통을 확인하는 데 도움이 됩니다. 물건 재활용은 정말 변화를 가져옵니다.

Q: 힙 분석기에서 생성자(그룹)의 내용은 무엇을 의미하나요?

  • (전역 속성) - 전역 개체(예: '창')와 이를 참조하는 개체 사이 중간 객체. 객체가 생성자 Person에 의해 생성되고 전역 객체에 의해 참조되는 경우 참조 경로는 [global] > (전역 속성) > 이는 서로를 직접 참조하는 객체와는 다릅니다. 성능상의 이유로 중간 개체를 사용합니다. 전역 개체는 자주 변경되며 비전역 변수의 속성 액세스 최적화는 전역 변수에 적용되지 않습니다.

  • (roots) - 생성자의 루트 내용은 선택한 개체를 참조합니다. 또한 엔진이 자동으로 생성한 참조일 수도 있습니다. 이 엔진에는 참조된 개체에 대한 캐시가 있지만 이러한 참조는 참조된 개체가 재활용되는 것을 방지하지 않으므로 진정한 강력한 참조(FIXME)가 아닙니다.

  • (클로저) - 일부 함수 클로저의 개체 집합에 대한 참조

  • (array, string, number, regexp) - 배열, 문자열, 숫자 또는 정규 표현식

  • (컴파일된 코드) - 쉽게 말하면 모든 것은 컴파일된 코드와 관련되어 있습니다. 스크립트는 함수와 비슷하지만 실제로는 3f1c4e4b6b16bbbd69b2ee476dc4f83a의 내용에 해당합니다. SharedFunctionInfo(SFI)는 함수와 컴파일된 코드 사이의 개체입니다. 함수에는 일반적으로 콘텐츠가 있지만 SFIS에는 없습니다(FIXME).

  • HTMLpElement, HTMLAnchorElement, DocumentFragment 등 – 코드.

이벤트 리스너 또는 사용자 정의 개체를 포함하여 프로그램 수명 주기 동안 생성된 다른 많은 개체는 다음 컨트롤러에서 찾을 수 있습니다.

Q: 메모리 분석을 수행할 때 영향을 미칠 수 있는 Chrome 기능을 꺼야 하나요?

메모리 분석을 위해 Chrome DevTools를 사용할 때는 모든 확장 프로그램을 끈 상태에서 시크릿 모드를 사용하거나 Chrome을 열기 전에 사용자 폴더를 (

)로 설정하는 것이 좋습니다. --user-data-dir=""

콘솔의 앱, 확장 프로그램, 심지어 기록까지 분석에 잠재적인 영향을 미칠 수 있으므로 이를 비활성화하세요.

마지막에 단어를 적어주세요

오늘날의 JavaScript 엔진은 이미 강력한 기능을 갖추고 있으며 코드에서 생성된 메모리 쓰레기를 자동으로 재활용할 수 있습니다. 즉, 지금까지만 갈 수 있지만 우리 애플리케이션은 여전히 ​​논리적 오류로 인해 메모리 누수가 발생하는 것으로 입증되었습니다. 적절한 도구를 사용하여 애플리케이션의 병목 현상을 찾고, 추측하지 말고 테스트해 보세요.

도움말 예

메모리 누수 진단

이 기사에서 많이 언급되었지만 메모리 관련 문제를 테스트하기 위한 일련의 예는 여전히 유용합니다. 아래는 세트입니다. DOM 노드 메모리 누수의 예. 더 복잡한 페이지나 애플리케이션을 테스트하기 전에 이러한 예제를 실험해 볼 수 있습니다.

  • 예 1: 메모리 증가

  • 예 2: 가비지 수집 실행

  • 예 3 : 분산된 객체

  • 예제 4: 분리된 노드

  • 예 5: 메모리 및 숨겨진 클래스es

  • 예 6: DOM 노드 유출

  • 예 7: Eval은 사악합니다(거의 항상)

  • 예 8 : 힙 할당 기록

  • 예 9: 예상보다 큰 DOM 누수

  • 예 10: 유지 경로

  • 예시 11: 마지막 연습

위 내용은 Chrome 개발자 도구의 JavaScript 메모리 분석에 대한 그래픽 소개의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.