measureUserAgentSpecificMemory()로 웹페이지의 총 메모리 사용량을 모니터링합니다.

프로덕션 환경에서 웹페이지의 메모리 사용량을 측정하여 회귀를 감지하는 방법을 알아보세요.

Brendan Kenny
Brendan Kenny
Ulan Degenbaev
Ulan Degenbaev

브라우저는 웹페이지의 메모리를 자동으로 관리합니다. 웹페이지에서 객체가 생성되면 브라우저는 '내부'에서 메모리 청크를 할당합니다. ~ 객체를 저장합니다 메모리는 유한한 자원이기 때문에 브라우저는 객체가 더 이상 필요하지 않은 시점을 감지하고 여유 공간을 기본 메모리 청크에 해당합니다

하지만 탐지가 완벽하지는 않습니다. 검증되었음이 증명되었습니다. 결코 쉬운 일이 아닙니다. 따라서 브라우저는 '객체'라는 개념을 필요합니다." '객체에 도달할 수 있다'는 개념으로 이루어집니다. 웹페이지에서 해당 변수와 다른 도달 가능한 객체의 필드를 통해 객체에 도달합니다. 브라우저가 객체를 안전하게 회수할 수 있습니다. 이러한 다음 예와 같이 메모리 누수가 발생합니다.

const object = {a: new Array(1000), b: new Array(2000)};
setInterval(() => console.log(object.a), 1000);

여기서 더 큰 배열 b는 더 이상 필요하지 않지만 브라우저는 콜백에서 object.b를 통해 여전히 도달할 수 있으므로 회수해야 합니다. 따라서 더 큰 배열의 메모리가 누출됩니다.

메모리 누수는 웹에서 흔히 발생합니다. 이벤트 리스너를 등록 취소하는 것을 잊어버리고 worker를 닫지 않고 iframe에서 객체를 실수로 캡처하는 경우 등의 작업을 수행합니다. 웹페이지에서 메모리 누수가 있는 경우 메모리 사용량이 점점 늘어나고 웹페이지가 느려지고 너무 커지게 됩니다

이 문제를 해결하는 첫 번째 단계는 그것을 측정하는 것입니다. 새로운 개발자는 performance.measureUserAgentSpecificMemory() API를 사용하여 다음 작업을 할 수 있습니다. 프로덕션 환경에서 웹페이지의 메모리 사용량을 측정하여 누출 가능성을 줄일 수 있습니다

performance.measureUserAgentSpecificMemory()는 기존 performance.memory API와 어떻게 다른가요?

기존의 비표준 performance.memory API에 익숙하다면 새 API와 어떻게 다른지 궁금하실 것입니다. 가장 큰 차이점은 이전 API는 JavaScript 힙의 크기를 반환하지만 새 API는 는 웹 페이지에서 사용된 메모리를 추정합니다. 이 차이는 Chrome이 여러 웹페이지와 같은 힙을 공유하는 경우 (또는 동일한 웹페이지의 여러 인스턴스) 이러한 경우 API가 임의로 사용 중지될 수 있습니다. 이전 API는 '힙'과 같은 구현 관련 용어를 표준화하기가 쉽지 않습니다.

또 다른 차이점은 새 API가 메모리 측정을 수행하는 동안 가비지 컬렉션입니다. 이렇게 하면 결과의 노이즈는 줄어들지만 결과가 생성될 때까지 다른 브라우저에서는 가비지 컬렉션에 의존하지 않고 새 API를 구현할 수 있습니다.

추천 사용 사례

웹페이지의 메모리 사용량은 이벤트, 사용자 작업 및 가비지 컬렉션입니다. 이러한 이유로 메모리 측정 API는 메모리 사용량 데이터를 집계하는 방법을 알아보겠습니다 개별 통화의 결과 덜 유용해집니다. 사용 사례 예:

  • 새로운 메모리 누수를 포착하기 위해 웹페이지의 새 버전 출시 중 회귀 감지
  • 메모리 영향을 평가하고 메모리 누수를 감지하기 위해 새로운 기능의 A/B 테스트입니다.
  • 메모리 사용량을 세션 기간과 연관시켜 메모리 누수가 있는지 확인합니다.
  • 메모리 사용량과 사용자 측정항목의 상관관계를 파악하여 메모리 사용량의 전반적인 영향을 이해합니다.

브라우저 호환성

브라우저 지원

  • Chrome: 89. <ph type="x-smartling-placeholder">
  • Edge: 89. <ph type="x-smartling-placeholder">
  • Firefox: 지원되지 않음 <ph type="x-smartling-placeholder">
  • Safari: 지원되지 않음 <ph type="x-smartling-placeholder">

소스

현재 이 API는 Chrome 89부터 Chromium 기반 브라우저에서만 지원됩니다. 이 브라우저가 여러 개이기 때문에 API의 결과는 구현에 따라 크게 달라집니다. 메모리에서 객체를 표현하는 다양한 방법과 메모리 사용량을 예측합니다 브라우저에서 일부 메모리 영역을 적절한 회계에 너무 많은 비용이 들거나 현실성이 없는 경우 회계 따라서 다음과 같은 결과가 나타납니다. 브라우저에서 비교할 수 없습니다. 이는 각 기간의 데이터를 동일한 브라우저에 대한 검색결과가 표시됩니다.

performance.measureUserAgentSpecificMemory() 사용

특성 감지

performance.measureUserAgentSpecificMemory 함수를 사용할 수 없거나 실행 환경이 충족되지 않으면 SecurityError와 함께 실패 교차 출처 정보 유출을 방지하기 위한 보안 요구사항 웹페이지가 활성화할 수 있는 교차 출처 분리에 의존합니다. COOP+COEP 헤더를 설정하면 됩니다.

지원은 런타임에 감지될 수 있습니다.

if (!window.crossOriginIsolated) {
  console.log('performance.measureUserAgentSpecificMemory() is only available in cross-origin-isolated pages');
} else if (!performance.measureUserAgentSpecificMemory) {
  console.log('performance.measureUserAgentSpecificMemory() is not available in this browser');
} else {
  let result;
  try {
    result = await performance.measureUserAgentSpecificMemory();
  } catch (error) {
    if (error instanceof DOMException && error.name === 'SecurityError') {
      console.log('The context is not secure.');
    } else {
      throw error;
    }
  }
  console.log(result);
}

로컬 테스트

Chrome은 가비지 컬렉션 중에 메모리를 측정하는데, API가 결과 프로미스를 즉시 확인하지 않고 대신 사용할 수 있습니다.

API를 호출하면 일정 시간 초과 후 가비지 컬렉션이 강제로 실행되며, 이는 현재 20초로 설정되어 있지만 더 빨리 발생할 수도 있습니다. Chrome을 시작할 때 --enable-blink-features='ForceEagerMeasureMemory' 명령줄 플래그로 제한 시간을 0으로 설정하고 로컬 디버깅 및 테스트에 유용합니다.

API의 권장 사용법은 전체 웹 페이지의 메모리 사용량을 샘플링하여 결과를 서버로 전송 통합 및 분석을 할 수 있습니다 가장 간단한 방법은 주기적 샘플링으로 예를 M분마다 하지만 이로 인해 데이터가 편향될 수 있습니다. 메모리 피크는 샘플 간에 발생할 수 있습니다.

다음 예는 다음을 실행하는 방법을 보여줍니다. 푸아송 프로세스를 사용하여 편향되지 않은 메모리 측정을 수행합니다. 샘플이 특정 시점에 발생할 가능성이 동일하게 보장됨 (데모, 출처)

먼저, 다음 메모리 측정을 예약하는 함수를 정의합니다. setTimeout()를 무작위로 지정합니다.

function scheduleMeasurement() {
  // Check measurement API is available.
  if (!window.crossOriginIsolated) {
    console.log('performance.measureUserAgentSpecificMemory() is only available in cross-origin-isolated pages');
    console.log('See https://web.dev/coop-coep/ to learn more')
    return;
  }
  if (!performance.measureUserAgentSpecificMemory) {
    console.log('performance.measureUserAgentSpecificMemory() is not available in this browser');
    return;
  }
  const interval = measurementInterval();
  console.log(`Running next memory measurement in ${Math.round(interval / 1000)} seconds`);
  setTimeout(performMeasurement, interval);
}

measurementInterval() 함수는 임의의 간격을 밀리초 단위로 계산합니다. 평균적으로 5분마다 한 번의 측정값이 있습니다 지수 함수 뒤에 숨겨진 수학에 관심이 있다면 분포를 선택합니다.

function measurementInterval() {
  const MEAN_INTERVAL_IN_MS = 5 * 60 * 1000;
  return -Math.log(Math.random()) * MEAN_INTERVAL_IN_MS;
}

마지막으로 비동기 performMeasurement() 함수는 API를 호출하고, 결과를 도출하고 다음 측정을 예약합니다.

async function performMeasurement() {
  // 1. Invoke performance.measureUserAgentSpecificMemory().
  let result;
  try {
    result = await performance.measureUserAgentSpecificMemory();
  } catch (error) {
    if (error instanceof DOMException && error.name === 'SecurityError') {
      console.log('The context is not secure.');
      return;
    }
    // Rethrow other errors.
    throw error;
  }
  // 2. Record the result.
  console.log('Memory usage:', result);
  // 3. Schedule the next measurement.
  scheduleMeasurement();
}

마지막으로 측정을 시작합니다.

// Start measurements.
scheduleMeasurement();

다음과 같은 결과가 표시될 수 있습니다.

// Console output:
{
  bytes: 60_100_000,
  breakdown: [
    {
      bytes: 40_000_000,
      attribution: [{
        url: 'https://example.com/',
        scope: 'Window',
      }],
      types: ['JavaScript']
    },

    {
      bytes: 20_000_000,
      attribution: [{
          url: 'https://example.com/iframe',
          container: {
            id: 'iframe-id-attribute',
            src: '/iframe',
          },
          scope: 'Window',
      }],
      types: ['JavaScript']
    },

    {
      bytes: 100_000,
      attribution: [],
      types: ['DOM']
    },
  ],
}

총 메모리 사용량 추정치는 bytes 필드에 반환됩니다. 이 값은 구현에 따라 크게 달라지므로 여러 브라우저에서 비교할 수 없습니다. 동일한 브라우저의 다른 버전 간에도 변경됩니다. 값에는 다음이 포함됩니다. 모든 iframe, 관련 창 및 웹 작업자의 자바스크립트 및 DOM 메모리는 확인할 수 있습니다

breakdown 목록은 사용된 메모리에 관한 추가 정보를 제공합니다. 각 항목은 메모리의 일부를 설명하고 메모리의 일부를 윈도우, iframe 및 작업자가 포함됩니다. types 필드에는 메모리와 관련된 구현별 메모리 유형입니다.

모든 목록을 일반적인 방식으로 처리하고 하드코딩하지 않는 것이 중요합니다. 가정을 기반으로 하지 않습니다. 예를 들어 일부 브라우저에서는 빈 breakdown 또는 빈 attribution를 반환합니다. 다른 브라우저에서도 attribution에서 다음 두 항목을 구별할 수 없음을 나타내는 여러 항목을 반환 어느 항목이 메모리를 소유하는지를 나타냅니다

의견

웹 성능 커뮤니티 그룹 및 Chrome팀의 의견 Google Ad Manager에 대한 performance.measureUserAgentSpecificMemory()입니다.

API 설계에 대해 알려주세요.

API에서 예상대로 작동하지 않는 부분이 있나요? 아니면 Google에서 누락된 속성이 있나요? 사양 문제 신고 performance.measureUserAgentSpecificMemory() GitHub 저장소를 확인하거나 기존 문제에 대한 생각을 알려주세요.

구현 문제 신고

Chrome 구현에서 버그를 발견하셨나요? 아니면 구현이 어떻게 해야 할까요? new.crbug.com에서 버그를 신고합니다. 반드시 최대한 자세히 설명하고 재현하기 위한 간단한 지침을 제공하세요. 버그를 해결하며 구성요소Blink>PerformanceAPIs로 설정해야 합니다. Glitch는 쉽고 빠른 재현을 공유하는 데 효과적입니다.

지지 표시

performance.measureUserAgentSpecificMemory() 서비스를 사용할 계획이신가요? 공익 활동 Chrome팀이 기능의 우선순위를 정하는 데 도움이 되고, 다른 브라우저 공급업체에 지원하는 것이 매우 중요합니다 @ChromiumDev로 트윗을 보내주세요. 어디서 어떻게 사용하는지 Google에 알려주세요.

유용한 링크

감사의 말씀

API 설계를 검토해 주신 Domenic Denicola, Yoav Weiss, Mathias Bynens에게 진심으로 감사드립니다. 및 Dominik Inführ, Hannes Payer, Kentaro Hara, Michael Lippautz 할 수 있습니다. Per Parker, Philipp Weis, Olga Belomestnykh, Matthew에게도 감사합니다. Bolohan과 Neil Mckay가 참여하신 분들께 API를 개선했습니다.

Unsplash해리슨 브로드벤트 히어로 이미지