2013-08-21 4 views
74

초당 60 회 호출되는 메인 루프가있는 매우 복잡한 자바 스크립트 앱을 사용하고 있습니다. Chrome 개발자 도구의 Memory 타임 라인에서 출력되는 'sawtooth'를 기반으로 한 가비지 수집이 많은 것처럼 보입니다. 이는 종종 애플리케이션의 성능에 영향을줍니다.자바에서 가비지 콜렉터 활동을 줄이는 모범 사례

그래서 가비지 수집기가 수행해야하는 작업량을 줄이는 모범 사례를 연구하려고합니다. (웹에서 찾을 수 있었던 대부분의 정보는 약간 다른 질문 인 메모리 누수를 피하는 것과 관련이 있습니다. 메모리가 사라지고 있습니다. 쓰레기 수거가 너무 많습니다.) 나는 추측하고 있습니다. 이것은 대부분 객체를 가능한 한 많이 재사용한다는 것이지만 악마는 세부 사항에 포함됩니다.

앱은 John Resig's Simple JavaScript Inheritance 줄을 따라 '클래스'로 구성됩니다.

한 가지 문제점은 몇 가지 기능이 초당 수천 번 호출 될 수 있다는 것입니다 (주 루프 반복마다 수백 번 사용됨). 아마도 이러한 함수의 로컬 작업 변수 (문자열, 배열 , 등) 문제가 될 수 있습니다.

나는 더 크고 무거운 물체에 대한 객체 풀링에 대해 알고 있습니다. (그리고 우리는이 정도를 사용합니다.) 특히 보드라는 이름의 함수와 관련하여 전반적으로 적용 할 수있는 기법을 찾고 있습니다. 시간이 긴 루프.

가비지 수집기에서 수행해야하는 작업량을 줄이기 위해 사용할 수있는 기술은 무엇입니까?

그리고 아마도 어떤 기술이 가비지 수집 대상이되는 개체를 식별하는 데 사용될 수 있습니까? (매우 큰 코드베이스이기 때문에 힙의 스냅 샷을 비교하는 것이 효과적이지는 않습니다.)

+2

우리에게 보여줄 수있는 코드의 예가 있습니까? 그 질문에 대답하기가 더 쉬워 질 것입니다. (덜 일반적이기 때문에 여기서는 확실하지 않습니다.) –

+0

외부 범위에서 변수를 사용하고 다시 사용할 수 있으므로 매번 다시 만들지 않아도됩니다. 예를 들어'var x = "longstring";을 루프에 넣으면 수천 개의 "longsting"이 생성되지만, 하나의 "longstring"만 생성됩니다. – Paulpro

+2

초당 수천 번 실행 기능을 중지하는 것은 어떻습니까? 이것이 정말로이 문제에 접근하는 유일한 방법입니까? 이 질문은 XY 문제처럼 보입니다. 당신은 X에 대해 설명하고 있지만 실제로 찾고있는 것은 Y에 대한 해결책입니다. –

답변

91

GC 혼란을 최소화하기 위해해야 ​​할 일은 대부분 다른 시나리오에서는 관용적 JS로 간주됩니다. 따라서 내가 제시 한 조언을 판단 할 때 상황을 명심하십시오.

할당은 여러 곳에서 현대적인 통역에 발생합니다

  1. new을 통해 또는 리터럴 구문 [...], 또는 {}를 통해 객체를 생성합니다.
  2. 문자열을 연결할 때.
  3. 함수 선언이 포함 된 범위를 입력 할 때.
  4. 예외를 트리거하는 작업을 수행 할 때.
  5. 함수 식을 계산할 때 (function (...) { ... }).
  6. 당신은 당신이 Array.prototype.slice처럼, 후드 아래에 다음 중 하나를 수행하는 내장를 호출 할 때 Object(myNumber) 또는 Number.prototype.toString.call(42)
  7. 처럼 Object로 강제 변환 작업을 수행합니다.
  8. arguments을 사용하여 매개 변수 목록에 반영 할 때.
  9. 문자열이나 일치 항목을 정규식으로 나눌 때.

가능한 경우 해당 작업을 수행하지 말고 개체를 저장하고 다시 사용하십시오. 폐쇄 오버 상태 밖으로 더 높은, 더 긴 수명 범위로에 없거나 약간의 종속성이 내부 기능을 당겨

  1. :

    는 특히, 기회를 밖을 봐. Closure compiler과 같은 일부 코드 마이너는 내부 함수를 인라인하여 GC 성능을 향상시킬 수 있습니다.

  2. 문자열을 사용하여 구조화 된 데이터 또는 동적 주소 지정을 나타내지 마십시오. 특히 각각 split 또는 정규식 일치를 사용하여 반복 구문 분석을 피하십시오. 이는 각각 여러 객체 할당이 필요하기 때문입니다. 조회 테이블과 동적 DOM 노드 ID의 키가 자주 발생합니다. 예를 들어 lookupTable['foo-' + x]document.getElementById('foo-' + x)은 문자열 연결이 있으므로 할당이 모두 필요합니다. 종종 다시 연결하는 대신 수명이 긴 오브젝트에 키를 첨부 할 수 있습니다. 지원해야하는 브라우저에 따라 Map을 사용하여 객체를 키로 직접 사용할 수 있습니다.
  3. 일반적인 코드 경로에서 예외를 catch하지 마십시오. try { op(x) } catch (e) { ... } 대신 if (!opCouldFailOn(x)) { op(x); } else { ... }을 입력하십시오.
  4. 문자열 생성을 피할 수없는 경우 (예 : 서버에 메시지를 전달하려면 JSON.stringify과 같은 내장 함수를 사용하십시오. 내부 원시 버퍼를 사용하면 여러 객체를 할당하는 대신 내용을 누적 할 수 있습니다.
  5. 빈도가 높은 이벤트에 콜백을 사용하지 말고 가능한 경우 콜백으로 메시지 내용의 상태를 다시 만드는 수명이 긴 함수 (1 참조)를 전달하십시오.
  6. arguments을 사용하는 함수는 해당 함수를 호출 할 때 배열과 같은 객체를 만들어야하므로 사용하지 마십시오.

나가는 네트워크 메시지를 만드는 데 JSON.stringify을 사용하시기 바랍니다. JSON.parse을 사용하여 입력 메시지를 구문 분석하는 것은 분명히 할당을 포함하고 대용량 메시지의 경우 많은 것을 포함합니다. 들어오는 메시지를 프리미티브의 배열로 나타낼 수 있다면 많은 할당을 줄일 수 있습니다. 당신이 할당하지 않는 파서를 만들 수있는 유일한 다른 내장 함수는 String.prototype.charCodeAt입니다. 복잡한 형식의 구문 분석기 만 사용하면 읽기에는 지옥이됩니다.

+0

'JSON.parse'd 객체가 메시지 문자열보다 적은 공간을 할당한다고 생각하지 않습니까? – Bergi

+0

@Bergi는 속성 이름에 별도의 할당이 필요한지 여부에 따라 다르지만 구문 분석 트리 대신 이벤트를 생성하는 파서는 관계없는 할당을 수행하지 않습니다. –

+0

환상적인 답변, 고마워요! 현상금이 만료되는 것에 대한 많은 사과 - 나는 그 당시에 여행 중이었고 어떤 이유에서든 내 휴대폰에 내 Gmail 계정으로 로그인 할 수 없었습니다 ..../ – UpTheCreek

9

일반적인 원칙으로 가능한 한 많이 캐시하고 루프를 실행할 때마다 생성 및 파기를 최소화해야합니다. .

내 머리 속에 떠오르는 첫 번째 문제는 익명 함수 (있는 경우)의 사용을 기본 루프 내부에서 줄이는 것입니다. 또한 다른 기능으로 전달되는 객체를 만들고 파괴하는 함정에 빠지기 쉽습니다. 나는 더는 자바 스크립트 전문가 의미가 아니지만, 나는이 것을 상상 :

var options = {var1: value1, var2: value2, ChangingVariable: value3}; 
function loopfunc() 
{ 
    //do something 
} 

while(true) 
{ 
    $.each(listofthings, loopfunc); 

    options.ChangingVariable = newvalue; 
    someOtherFunction(options); 
} 

이보다 빠르게 실행됩니다 :

while(true) 
{ 
    $.each(listofthings, function(){ 
     //do something on the list 
    }); 

    someOtherFunction({ 
     var1: value1, 
     var2: value2, 
     ChangingVariable: newvalue 
    }); 
} 

적 프로그램에 대한 다운 타임이 있습니까? 두 번째 또는 두 번째 (예 : 애니메이션)에 원활하게 실행해야하고 처리하는 데 더 많은 시간이 필요합니까? 이 경우 일반적으로 애니메이션 전체에서 가비지 수집되는 개체를 가져 와서 일부 전역 개체에서 참조를 유지하는 것을 볼 수 있습니다. 그런 다음 애니메이션이 끝나면 모든 참조를 지우고 가비지 컬렉터가 작업을 수행하게 할 수 있습니다.

죄송합니다.이 모든 것이 이미 시도하고 생각한 것과 비교하면 조금 사소한 것입니다.

+0

이것은. 또한 다른 기능 (IIFE가 아닌)에서 언급 된 기능은 많은 메모리를 소모하고 놓치기 쉬운 일반적인 남용입니다. – Esailija

+0

크리스! 불행히도 가동 중지 시간이 없습니다 :/ – UpTheCreek

5

global scope (가비지 컬렉터가이 부분을 터치 할 수없는 곳)에 하나 이상의 객체를 만들면 내 솔루션에서 리팩터링하여 해당 객체를 사용하여 작업을 완료하도록하려고합니다. 지역 변수를 사용하는 대신

물론 코드에서 모든 부분에서 코드를 수행 할 수는 없지만 일반적으로 가비지 수집기를 피하기위한 방법입니다.

P. 코드의 특정 부분을 조금만 유지 보수 할 수 있습니다.

+0

GC가 내 전역 범위 변수를 일관되게 취합니다. – VectorVortec

8

크롬 개발자 도구는 메모리 할당 추적 기능이 매우 뛰어납니다. 그것은 메모리 타임 라인이라고 불립니다. This article에는 몇 가지 세부 정보가 나와 있습니다. 이게 "톱니"에 대한 얘기 야? GC'ed runtimes 대부분의 정상적인 동작입니다. 사용 임계 값에 도달하여 컬렉션을 트리거 할 때까지 할당이 진행됩니다. 일반적으로 서로 다른 임계 값에 따라 다른 종류의 컬렉션이 있습니다.

Memory Timeline in Chrome

쓰레기 컬렉션은 자신의 시간과 함께 추적과 관련된 이벤트 목록에 포함되어 있습니다. 내 오래된 노트북에서 임시 컬렉션은 약 4Mb에서 발생하며 30ms가 소요됩니다. 이것은 60Hz 루프 반복의 2 개입니다. 애니메이션 인 경우 30ms 컬렉션이 더듬 거리는 원인이 될 수 있습니다. 현재 환경에서 벌어지는 일들을보기 위해 여기에서부터 시작해야합니다. 컬렉션 임계 값은 어디에 있으며 컬렉션이 차지하는 기간입니다. 이렇게하면 최적화를 평가하기위한 참조 점이 제공됩니다. 하지만 할당 비율을 줄여 콜렉션 간의 간격을 길게하여 더듬 거리는 빈도를 줄이는 것보다 더 나은 방법은 없을 것입니다.

다음 단계는 프로필 | 레코드 힙 할당 기능은 레코드 유형별로 할당 카탈로그를 생성합니다. 이렇게하면 추적 기간 동안 할당 비율과 동일한 가장 많은 메모리를 소비하는 개체 유형이 빠르게 표시됩니다. 비율에 따라 내림차순으로 초점을 맞 춥니 다.

기술은 로켓 과학이 아닙니다. 상자 안의 물건을 사용하지 않을 때는 박스가없는 물건을 피하십시오. 전역 변수를 사용하여 반복 할 때마다 새 변수를 할당하는 대신 단일 boxed 객체를 보유하고 다시 사용하십시오. 공용 객체 유형을 버리기보다는 자유 목록에 저장하십시오. 이후의 반복에서 재사용 할 가능성이 높은 캐시 문자열 연결 결과. 대신 엔 클로징 범위에 변수를 설정하여 함수 결과를 반환하는 할당을 피하십시오. 최상의 전략을 찾으려면 각 오브젝트 유형을 자체 컨텍스트에서 고려해야합니다. 세부 사항에 대한 도움이 필요한 경우,보고있는 도전의 세부 사항을 설명하는 편집을 게시하십시오.

샷건에서 응용 프로그램 전체에 걸쳐 일반적인 코딩 스타일을 왜곡하지 말고 쓰레기 수거를 줄이는 것이 좋습니다. 이는 속도를 성급하게 최적화해서는 안되는 것과 같은 이유 때문입니다. 대부분의 노력과 코드의 복잡성과 모호함의 상당 부분은 의미가 없습니다.

+0

바로 그게 톱니가 의미하는 것입니다. 항상 톱니 모양의 패턴이 있다는 것을 알고 있지만 내 관심사는 톱니파와 벼랑이 상당히 높다는 것입니다. 흥미롭게도 GC 이벤트는 내 타임 라인에 표시되지 않습니다. '레코드'창 (가운데)에 나타나는 유일한 이벤트는 '요청 애니메이션 프레임', '애니메이션 프레임 실행 됨'및 '합성 레이어'입니다. 왜 내가 GC 이벤트를 보지 못하는지 잘 모르겠다. (이것은 최신 버전의 크롬과 카나리아이다.) – UpTheCreek

+2

'프로파일 힙 할당'을 사용하여 프로파일 러를 사용해 보았지만 매우 유용하지는 않습니다. 아마도 제대로 사용하는 방법을 모르기 때문일 수 있습니다. '@ 342342 '와'code relocation info'와 같이 나에게 아무런 의미가없는 참조로 가득 찬 것처럼 보입니다. – UpTheCreek