"번역"JS 엔진의 핵심 : 프로토 타입 최적화

이 문서는 재현 원숭이 2048 웹 사이트 ➱ https://www.mk2048.com/blog/blog.php?id=hc01b0jkjb

원본 링크 : 자바 스크립트 엔진 기본 : 최적화 프로토 타입

자서

이 시리즈는 JS 엔진에 사용되는 코어 설계에 초점을 맞추고있다. 이 문서의 저자는 V8 엔진 개발자이다 베네딕트마티아스 하지만, 걱정하지 마세요, 컨텐츠는 모든 주요 JS 엔진에 적용 할 수있다. JS 개발자로, JS 엔진은 당신을 도울 수있는 방법에 대한 깊이있는 이해는 자신의 코드의 성능 특성의 일부를 해석합니다.

이전 기사 (에서 원본 , 번역 ), 우리는 (참조하시기 바랍니다 특정 원칙에 같은 데이터 구조의 이름으로 기사를 V8을 모양) (JS 엔진 모양을 사용하는 방법을 논의 잠정 번역 내 인라인 캐시 관련 캐시, 즉 동일한 원리에 기사를 참조하여, 데이터 액세스 성능 구조를 최적화하는 방법)은 객체의 배열로의 액세스 성능을 최적화한다. 이 문서에서는 설명합니다 파이프 라인에 최적화 트레이드 오프를 어떻게 프로토 타입 속성 액세스의 엔진 성능을 최적화 할 수 있습니다.

** 팁 : ** 배우고 비디오를 볼 것을 선호하는 경우,이 문서가 직접보고 건너 뛸 수 있습니다 비디오 . (이 신 우유를 사용하는 것이 좋습니다, 사다리를 필요)

레벨 최적화 및 구현 트레이드 오프 (최적화 계층 및 실행 절충)

우리의 마지막 기사는 같은 파이프 라인 디자인의 실행이 현대 JS 엔진에 대해 설명합니다 :

JS 엔진 파이프 라인

우리는 또한 지적 엔진 최적화 전체 디자인 사이의 파이프 라인은 여전히 ​​점에서 약간의 차이가되는 동일하지만 그. 이유는 무엇입니까? ** 왜 일부 엔진은 다른 엔진 최적화 수준보다 그 이상을 사용? ** 우리는 얻을 결국 다음 시간을 소비하고 가능한 빨리 코드의 구현의 시작과 트레이드 오프 고성능 코드 실행 사이에 있다는 것을 이해합니다.

트레이드 오프-시작 속도

통역 (통역) 빠른 바이트 코드 속성 (바이트 코드)하지만 바이트 코드는 일반적으로 매우 효율적이지 않습니다. 좋은 최적화 컴파일러 (최적화 컴파일러) 조금 더 시간이 걸릴 것입니다,하지만 최종 출력은 매우 효율적인 기계 코드 (기계 코드)에 비해.

이는 사용중인 모델의 V8 엔진입니다. V8 엔진 통역 점화라는, 그는 (단지 용어에 대하여 바이트 코드 실행 속도) 현재 인터프리터 내부의 모든 엔진의 빠른입니다. V8의 최적화 컴파일러는 그는 결국 고도로 최적화 된 머신 코드를 얻을 것이다, 터보 팬이라고합니다.

트레이드 오프-시작 속도-V8

시작 시간과 속도 사이의 트레이드 오프 기다린는 중앙에서의 수준을 높이기 위해 JS 엔진 최적화를 선택하는 이유 중 일부입니다. 그들과 최적화 컴파일러 사이의 예를 SpiderMonkey를 인터프리터를 들어 IonMonkey은 기준 층 증가했다.

트레이드 오프 - 시작 - 속도의 SpiderMonkey

빠른 출력 통역 바이트 코드 만 바이트 코드 실행 속도가 상대적으로 느립니다. 베이스 라인은 코드를 생성하기 위해 조금 더 많은 시간을 보내고, 또한 더 나은 런타임 성능을 제공합니다. 그런 다음 IonMonkey 런타임에 있지만 정말 효율적인 출력 시스템 코드, 기계 코드를 더 많은 시간을 보낼 것입니다.

우리 서로 다른 엔진 작동 파이프 라인에서 구체적인 예를 들어 보면 다루는 다른 무엇 보자. 다음은 긴 사이클 기간의 코드가 계속 실행된다.

let result = 0;
for (let i = 0; i < 4242424242; ++i) {
	result += i;
}
console.log(result);

V8 먼저 점화 바이트 코드 인터프리터에서 실행됩니다. 그리고 어떤 점에서, 엔진이 상대적으로 핫 코드 (종종 실행)을 발견 할 것이다, 엔진은 터보 팬 전면 (프론트 엔드)를 시작합니다. 전경은 터보 팬의 일부는 터보 팬, 그 코드의 구조를 설명하는 결합 처리를 리드 통계 데이터 및 기계의 기단을 구성한다. 터보 후속 최적화를위한 다른 스레드 (최적화)에 전면 출력 터보 최적화로 전송한다 후에.

파이프 라인 세부-V8

최적화의 최적화 동안, V8은 점화가 바이트 코드를 실행 계속 사용합니다. 최적화가 그의 작품을 완성 할 때 우리가 실행 기계 코드를 얻을 수 있습니다, 기계 코드는이 논리 후 계속 사용됩니다.

의 SpiderMonkey 엔진은 최초의 바이트 코드 인터프리터에서 실행됩니다. 그러나 그는 하나의 기준선 층, 첫 번째 코드가베이스 라인에 전송됩니다 너무 뜨거워있다. 베이스 라인 컴파일러 (컴파일러) 기준은 실행 논리를 계속 주 스레드에서 생성 된 코드를 최적화합니다.

파이프 라인 디테일의 SpiderMonkey

코드가베이스 라인 후 여러 번 실행되는 경우, SpiderMonkey를 결국 IonMonkey 전면 (프론트 엔드)를 시작하고, 자신의 최적화 (최적화)를 자극한다. 그리고이 V8 엔진과 매우 유사합니다. IonMonkey이 최적화를 완료 할 때까지 코드의 기본 구현은 여전히 ​​약간의 시간이 될 것입니다. 코드의 최적화 후 손실 기준 코드 실행을 대체합니다.

차크라 아키텍처와 SpiderMonkey를 매우 유사합니다. 차이점은 차크라는 메인 스레드를 차단하지 않도록 병렬로 실행하는 데 더 많은 콘텐츠를 좀하려고합니다. 그래서 차크라 어떤 컴파일러 구성 요소의 주 스레드에서 실행되지 않습니다, 그는 복사 데이터를 컴파일러가 사용할 필요하고 특별한 컴파일 과정에 데이터를 전송 할 수 바이트 코드를 분석하기로 결정했습니다.

파이프 라인 - 세부 - 차크라

코드 생성이 완료되면, 엔진 대신 SimpleJIT 바이트 코드 전에 코드 (차크라 컴파일러 중간층 최적화)를의 실행됩니다. 작업의 FullJIT (차크라 맨 최적화 컴파일러) 모드는 동일합니다. 이 방법의 이점은 사본 제작 일시 정지 시간이 전체 런타임 컴파일러 나 컴파일러 프런트 데스크보다 훨씬 더 짧아집니다 번. 그러나이 방법은 충분 ** 복사 추론 (지능형 복사) ** 실제 최적화 과정 유용한 데이터의 일부 누락이 발생할 수 있습니다. 어느 정도 그래서, 또한 코드 품질 및 드웰 시간 사이의 트레이드 오프로 볼 수있다.

JavaScriptCore는, 모든 최적화 컴파일러는 완전 병렬 JS 실행에, 카피 링크가 없습니다! 메인 스레드는 다른 스레드를 컴파일 (트리거) 컴파일 작업을 트리거합니다. 컴파일러 후 주 스레드에서 데이터 분석에 액세스하기 위해 복잡한 잠금 구조를 사용합니다.

파이프 라인 - 세부 - JavaScriptCore는

이 방법의 장점은 그가 주 스레드에서 코드 최적화의 오버 헤드를 감소한다는 것입니다. 이 방법은 복잡한 멀티 스레딩 문제의 부족을 소개하고, 또한 많은 작업을 가져 때 스레드 잠금을 수행하는 오버 헤드를해야합니다.

우리는 이전 코드를 확인하고보다 효율적인 코드 실행 사이에 만들기 위해 최적화 컴파일러를 사용하여 시작하는 통역의 사용과 관련하여 전술 절충을 많이 가지고 있어요. 그러나 또 다른 트레이드 오프가 존재입니다 - 메모리 오버 헤드 ! 더 생생하게이 점을 이해하기 위해서, 우리는 다음과 같은 코드를 볼. 이 코드의 내용은 단지 두 개의 번호를 추가, 매우 간단합니다.

function add(x, y) {
	return x + y;
}

add(1, 2);

여기에서 우리는 점화 V8 발생 해석의 바이트 코드 추가 방법을 사용하십시오

StackCheck
Ldar a1
Add a0, [0]
Return

이 바이트 코드는 실제로 무엇을 의미하는지 상관 없어, 중요한 점은이는 점이다 네 개의 코드 라인 !

코드가 고온이되면, 터보 팬이 높은 다음 후 최적화이의 기계 코드를 생성합니다 :

leaq rcx,[rip+0x0]
movq rcx,[rcx-0x37]
testb [rcx+0xf],0x1
jnz CompileLazyDeoptimizedCode
push rbp
movq rbp,rsp
push rsi
push rdi
cmpq rsp,[r13+0xe88]
jna StackOverflow
movq rax,[rbp+0x18]
test al,0x1
jnz Deoptimize
movq rbx,[rbp+0x10]
testb rbx,0x1
jnz Deoptimize
movq rdx,rbx
shrq rdx, 32
movq rcx,rax
shrq rcx, 32
addl rdx,rcx
jo Deoptimize
shlq rdx, 32
movq rax,rdx
movq rsp,rbp
pop rbp
ret 0x18

이것은 우리가 그와 상위 4 선 바이트 코드에 단어의 비교입니다, 특히, 정말 코드의 긴 목록입니다! 일반적으로, 바이트 코드의 의미는 최적화가에 대한, 특히, 컴퓨터 코드, 기계 코드보다 더 복잡한 경향이 있습니다. 한편, 그를 수행하는 바이트 코드 해석기가 필요하고, 최적화 된 머신 코드를 직접, 프로세서에 의해 실행될 수있다.

이것은 또한 "모든 코드를 최적화 '로 이동하지 않습니다 주요 JS 엔진 중 하나입니다. 우리가 배운 전에,도에서 찾을 수 있습니다 우리는 위의 경우를 만들어, 최적화 된 머신 코드는 다음으로, 시간이 오래 걸립니다 생성 더 많은 메모리를 소모합니다 최적화 된 코드 .

트레이드 오프 메모리

요약 : 때문에 코드를 이전하고 트레이드 오프 사이의보다 효율적인 코드 실행을 위해 최적화 컴파일러를 사용하기 위해 통역을 사용할 필요의, 수준의 다른 번호가 왜 다른 JS 엔진 최적화 이유. 이것은 선택의 규모 문제입니다, 당신은 추가 비용 등의 복잡성에 더 세분화 된 선택을 할 수 있도록 더 최적화 레벨을 추가 할 수 있습니다. 이것의 위에, 그리고 트레이드 오프 메모리 계층 최적화 및 최적화 코드의 비용 사이에있다. JS 엔진이 뜨거운 사람들의 방법을 최적화하기 위해 노력할 것입니다 이유입니다.

액세스 성능 최적화 prototype 속성

우리의 마지막 기사는 JS 엔진이 개체 속성의 모양 및 인라인 캐시를로드하는 데 최적화되어 사용하는 방법에 대해 설명합니다. 이 아래로 비등, 특정 모양의 내용과 객체 엔진이 떨어져 개체됩니다.

모양 -2-

형상 (ICS로 약칭 될 수있다)이다 인라인 캐시 호출이 최적화 방법을 가져왔다. 둘의 조합으로, 당신은 속도를 높일 수 있습니다 로컬 코드가 같은 객체 속성에 대한 액세스를 반복한다.

IC-4

프로토 타입 기반 프로그래밍 클래스와

클래스 (클래스) : 이제 우리는 더 빨리 객체의 속성에 액세스하는 방법을 알고, 우리는 곧 몇 합류 JS의 가족을 볼 것이다. 아래 구문 JS에서 정의 된 클래스이다.

class Bar {
	constructor(x) {
		this.x = x;
	}
	getX() {
		return this.x;
	}
}

이 JS 새로운 개념처럼 보이지만 실제로 프로토 타입 프로그래밍에 단지 문법 설탕된다. 대법 프로토 타입 상속은 여전히 ​​깊이 영원히 지속 뿌리를두고있다.

function Bar(x) {
	this.x = x;
}

Bar.prototype.getX = function getX() {
	return this.x;
};

여기서 우리는 이름 지정 getX받는 사람 속성 Bar.prototype개체를. 때문에 다른 개체가 동일한에 할당 된 JS 프로토 타입은 또한 객체 ! 이러한 유사한 JS 프로토 타입 기반 프로그래밍 언어에서, 프로토 타입 방법에 의해 공유 될 수는 특정 필드는 객체 인스턴스 자체에 저장된다.

그럼 우리가 호출 만들 때의 우리의 깊이를 살펴 보자 무슨 일이 일어나고 있는지 때 뒤에 인스턴스를.fooBar

const foo = new Bar(true);

이 코드 생성 예제 만있는 'x'필드의 모양입니다. foo프로토 타입 Bar.prototype클래스에 속한다 Bar.

클래스 모양-1

이것은 Bar.prototype그가 가지고, 자신의 모양을 가지고 'getX'그 기능 값을 반환하는 것입니다 필드 this.x방법 getX. Bar.prototype프로토 타입은 Object.prototype그가 JS 언어 기반의 일부입니다. Object.prototype프로토 타입은 전체 트리의 루트입니다, 그래서 그는 프로토 타입입니다 null.

클래스 모양-2

우리가 전에 말한대로, 같은 클래스의 다른 인스턴스를 만들 경우, 두 개의 인스턴스는 같은 모양을 공유합니다. 프로토 타입의 두 가지 예는 같은 가리 킵니다 Bar.prototype객체입니다.

액세스 prototype 속성

자, 이제 우리는 우리가 클래스를 정의 할 때, 언제 무슨 일이 있었는지 뒤에 인스턴스를 만들 수 있음을 이해합니다. 우리는 인스턴스 때 뒤의 메소드를 호출 할 때 어떤 일이 다음 일이? 이 예처럼, 코드를 다음 :

class Bar {
	constructor(x) { this.x = x; }
	getX() { return this.x; }
}

const foo = new Bar(true);
const x = foo.getX();
//        ^^^^^^^^^^

다음과 같은 두 단계를 구상의 메서드를 호출 할 수 있습니다 :

const x = foo.getX();

// is actually two steps:

const $getX = foo.getX;
const x = $getX.call(foo);

첫 번째 단계는 (그 값은 함수) 프로토 다만 속성이 방법을로드한다. 두 번째 단계는 현재의 예이며 this,이 함수를 호출한다. 의 특정 첫 번째 단계는 살펴 보겠습니다 getX에서 방법 foo의 예를 읽고.

방법 부하

엔진 시동 foo인스턴스를 찾을, 시작 foo형상에와 찾지 못했습니다 'getX'속성을, 그래서 그는 프로토 타입 체인 추적을 수행 할 필요가있다. 그런 다음 우리는에 액세스 할 수있는 Bar.prototype자신의 프로토 타입 모양에, 우리가 발견, 'getX'오프셋 위치에있는 재산 0에 있습니다. 우리는 방문 Bar.prototype발견이 비트 오프셋 값에 JSFunction getX우리가 원하는이다!

JS 유연성은, 예를 들어, 우리에게 다음 코드를 프로토 타입 체인을 수정하는 방법을 제공합니다 :

const foo = new Bar(true);
foo.getX();
// → true

Object.setPrototypeOf(foo, null);
foo.getX();
// → Uncaught TypeError: foo.getX is not a function

이 예제에서, 우리는 전화를 foo.getX()두 번,하지만 때마다 의미와 결과는 완전히 다릅니다. 이 이유는 JS 또한 단지 일반 객체의 프로토 타입,하지만 JS 엔진은, 프로토 타입 속성이 더 많은 도전에 액세스하는 개체의 자신의 재산의 속도보다 더 빠른 가속 접근을 가속화하는 있지만.

JS는 그 프로그램에서, 부하 프로토 타입 속성은 매우 일반적인 작업입니다 : 때마다 당신은 인스턴스 메서드가 일어날 것입니다 전화!

class Bar {
	constructor(x) { this.x = x; }
	getX() { return this.x; }
}

const foo = new Bar(true);
const x = foo.getX();
//        ^^^^^^^^^^

우리는 이미 두 가지 방법을 셰이프를 사용하여 인라인 캐시하여 자신의 재산의 일반 객체에 엔진 로딩 속도를 최적화하는 방법을 논의하기 전에. 우리는 어떻게 객체 그것의 원형 모양에서 유사한 특성을 가지고 호출을 반복 최적화 할 수 있습니까? 우리는 위의 속성 액세스에 설명했다 어떻게 이루어집니다.

프로토 타입로드 검사-1

반복 호출이 특정 조건을 가속화하기 위해, 우리는 먼저 다음 세 가지를 결정해야합니다 :

  1. foo어떤 객체없는 모양 'getX'속성을 변경하지 않습니다. 객체 foo에 추가하거나 속성의 속성 등의 내용 변화없이 변화하고 삭제하는 것이 의미.
  2. foo프로토 타입은 여전히 원래이다 Bar.prototype. 실패의 의미 Object.setPrototypeOf()또는 _proto_변경하는 속성이 할당 foo프로토 타입을.
  3. Bar.prototype셰이프 소유 'getX'재산 및 변화 없음. 의미 Bar.prototype추가하거나 속성의 내용은 변경이 발생 특성 변화 삭제할 수 없습니다.

일반적으로, 이것은 우리가 두 번 해본이 부동산에 검사를 찾을 때까지 우리는 다음 플러스 각 프로토 타입 프로토 타입 체인에 대한 검진을 위해 인스턴스 자체에있을 필요가 있다는 것을 의미한다. 아마 당신은 생각하는 1 개 + 2N 검사 문제를 느끼지 않았다 (N 관여 중간 프로토 타입의 수),하지만 당신은 엔진이 정기적으로 더 이상이 비교 충족, 실제로 상대적으로 얕은이 프로토 타입 체인의 예를 알아야 프로토 타입 체인. 비 유적으로는 DOM 클래스는 일반적인 예입니다. 다음 코드를 살펴 보자 :

const anchor = document.createElement('a');
// → HTMLAnchorElement

const title = anchor.getAttribute('title');

우리가 만든 HTMLAnchorElement그의 호출 getAttribute()방법. 이 간단한 프로토 타입 체인 앵커 요소는 여섯 프로토 타입을 소개되었습니다! 가장 흥미로운 DOM 조작은 직접하지 않습니다 HTMLAnchorElement프로토 타입, 프로토 타입 체인하지만 더 상단에 위치.

앵커 - 프로토 타입 체인

당신은 것 Element.prototype찾기 getAttribute()방법을. 이것은 우리가 전화를 할 때마다 것을 의미한다 anchor.getAttribute()시간, JS 엔진이 필요 ...

  1. 확인 'getAttribute'에 존재하지 않는 anchor대상,
  2. 프로토 타입은 다음 단계로 가져 오기 HTMLAnchorElement.prototype,
  3. 체크 'getAttribute'이 계층의 프로토 타입을하지,
  4. 프로토 타입은 다음 단계로 가져 오기 HTMLElement.prototype,
  5. 확인 'getAttribute'이 층을 더 이상 프로토 타입을,
  6. 마지막으로 프로토 타입은 다음 레벨로 Element.prototype,
  7. 그 위에 마지막으로 발견 'getAttribute'.

7 단계 검사의 총! 이 코드 유형은 웹 프로그래밍에서 정말 매우 일반적인 경우, 엔진은 프로토 타입 속성에 액세스하는 데 필요한 검사의 수를 줄이기 위해 몇 가지 팁을 사용합니다.

우리가 이전 예제로 돌아가 보자, 우리는 방문 세 번 속성을 확인 총을 :foo'getX'

class Bar {
	constructor(x) { this.x = x; }
	getX() { return this.x; }
}

const foo = new Bar(true);
const $getX = foo.getX;

마지막으로 우리는 프로토 타입을 필요 속성을 각 개체 속성을 발견하기 전에 우리는 모양을 확인해야합니다. 우리가 길에게 검사의 수를 확인하는 재산으로 확인 스토리지 프로토 타입을 감소시킬 수있는 경우, 일부 성능을 최적화 할 수 있습니다. 이 기술은 일반적으로 엔진이 사용된다 : 엔진 프로토 타입은 A의 모양을 참조 아닌 인스턴스 자체에 저장됩니다 .

프로토 타입 부하 검사 - 2

모든 모양은 프로토 타입을 가리 킵니다. 이것은 또한 때마다 것을 의미 foo프로토 타입 변경, 엔진이 그에게 새로운 형태로 대체됩니다. 이제 우리 중 하나는 당신이 그것의 모양 개체를 확인해야합니다, 프로토 타입에 부동산 취득 또는 기준의 존재를 확인합니다.

이 방법을 통해, 우리는 프로토 타입 속성 액세스에서 필요한 검사의 수를 가속화 할 수 있습니다 1+2N시간을 줄여 1+N시간을. 이 모든 것이 상대적으로 선형 프로토 타입 체인의 깊이를 증가 후 그러나이 지출은 여전히 커지고있다. 엔진은 속성 액세스은 종종 그 작업 이후에 실행됩니다 특히 들면, 고정 된 수에 검사의 수를 줄이기 위해 가능한 한 많이 얻기 위해 몇 가지 추가 방법을 구현합니다.

유효성 검증 부 (유효 셀)

이를 위해 V8은 모양의 프로토 타입은 특별한 거래를했다. 각 프로토 타입은 각각 특별한 프로토 타입의 모양이, 모양은 (특히 다른 프로토 타입와 공유하지 않음) 다른 개체와 공유되지 않은 독특한 모양을 가지고 ValidityCell그와 관련된합니다.

validitycell

이 때마다 ValidityCell변화의 발생, 또는 프로토 타입의 상위 계층과 관련된 프로토 타입 장소 변경을했다, 그는 잘못된 태그 것이다. 우리가 모든 과정을 살펴 보자하는 방법 특정 종류이다.

프로토 타입 속성 액세스의 후속 속도를 높이기 위해, V8은 네 개의 필드와 인라인 캐시를 만듭니다

IC-validitycell

인라인 캐시 예열 시간을 할 수있는 첫 번째 실행 코드에서, V8은 프로토 타입 객체 (이 예에서는이 속성이 속해있는 프로토 타입 속성의 오프셋 (offset) 위치 기록 Bar.prototype이 예에서) Shape의 현재 인스턴스를 ( 되고 foo도형) 및 현재 인스턴스 형상 가까운 원형 현재 유효성 검증 기준 부 (이 예에 Bar.prototype유효성 검증)을 의미한다.

이 인라인 캐시의 발효 명중되어 다음 번에, 엔진은 먼저 자신뿐만 아니라 모양의 현재 인스턴스를 확인합니다 ValidityCell. 마크는 여전히 유효하면, 당신은 녹음하여 여분의 엔진 쿼리를 건너 뛸 수 属性位置偏移量(Offset)属性所属原型对象(Prototype)이 속성에 대한 액세스를.

validitycell - 무효

때문에 변화의 프로토 타입이 새로운 Shape가 발생합니다 때 프로토 타입에 할당하고, 그 원래되어 ValidityCell유효하지 않은 것으로 표시됩니다. 이러한 방법으로 다음 실행 인라인 캐시는 낮은 액세스 성능의 결과로 역할을 할 수 없습니다.

의 이전 예를 들어, DOM 요소로 돌아 가자. 우리가 할 경우 Object.prototype수정할 수, 그것은 맨발하지 않을 Object.prototype자신이 다음 것, 자신의 인라인 캐시가 유효하지 않은 것으로 표시되어 EventTarget.prototype, Node.prototype, Element.prototype등까지 HTMLAnchorElement.prototype인라인 캐시 프로토 타입 지금까지 잘못 표시됩니다.

프로토 타입 체인 validitycells

따라서, 런타임에 수정하는 Object.prototype성능을 포기 기본적인 동등합니다. 그래서 그것을하지 않습니다!

의는 특정 모양에 대해 알아 예를 사용하자. 이제이 Bar클래스는, 함수가 loadX바의 메소드를 호출하는 것입니다. 우리는 여러 번 호출이 클래스의 여러 인스턴스를 전달합니다 loadX이 기능을 사용하지 않음.

class Bar { /* … */ }

function loadX(bar) {
	return bar.getX(); // IC for 'getX' on `Bar` instances.
}

loadX(new Bar(true));
loadX(new Bar(false));
// IC in `loadX` now links the `ValidityCell` for
// `Bar.prototype`.

Object.prototype.newMethod = y => y;
// The `ValidityCell` in the `loadX` IC is invalid
// now, because `Object.prototype` changed.

loadX함수 인라인 캐시는 이제 가리키는 . 당신이 유사한 수정 뒤에 할 경우 이러한 작업, JS의 모든 프로토 타입 체인의 루트,이 작업은 우리가 만들 것입니다 무효가, 당신은 지금 인라인 캐시 히트 다음에, 그는 어떤 역할을 없었다. 인라인 캐시 최적화를 분실, 우리는 낮은 액세스 성능으로 돌아갈 수 있습니다.Bar.prototypeValidityCellObject.prototypeObject.prototypeValidityCell

수정 Object.prototype방법은 항상 추천, 모든 프로토 타입 속성 액세스 인라인 캐시 그 시점이 잘못되기 전에 만들어진이 것 엔진이 아니다. 우리가 다른 살펴 보자 하지 말아야 할 무엇의 예를 :

Object.prototype.foo = function() { /* … */ };

// Run critical code:
someObject.foo();
// End of critical code.

delete Object.prototype.foo;

우리는 먼저 확장 Object.prototype모든 프로토 타입 엔진 인라인 캐시는이 오류가 발생하기 전에 생성 원인이되는. 그리고 우리는 몇 가지 호출이 새로운 프로토 타입 방법 코드를 실행했습니다. 이 기간 동안, 엔진은 처음부터 다시 시작하고 모든 속성 액세스에 대한 쿼리 인라인 캐시 프로토 타입을 생성합니다. 마지막으로, 우리는 현장을 취소 프로토 타입 방법은 이전에 추가 제거.

정리는 바로, 좋은 생각 같은 소리? 그러나이 시나리오에서 그는 단지 상황을 악화시킬 것입니다! 다시 변경 속성 작업을 삭제 Object.prototype하여 모든 인라인 캐시 방금 만든 다시 한번 실패, 엔진이 쿼리에서 그것을 다시 시작해야합니다.

** 요약 : ** 단지 프로토 타입 객체 비록,하지만 그들이 가지고 있기 때문에 특별한 치료 프로토 타입을 찾을 JS 엔진의 성능을 최적화하기 위해서이다. 이러한 프로토 타입을 만지지 마세요! 당신이 정말로 프로토 타입을 변경해야하는 경우 다른 코드를 실행하기 전에 적어도 코드가 실행 중일 때 최적화 엔진을 모두 무효화되지 않도록, 다음, 변경을 완료하시기 바랍니다.

소 결 (Take-aways)

우리는 JS 엔진이 엔진은 프로토 타입의 동작을 최적화하기 위해 모양, 인라인 캐시 및 ValidityCells을 사용하는 방법입니다 된 개체를 저장하고 수업 방법입니다 배웠습니다. 이 지식을 바탕으로, 우리는 JS 프로그래밍 연습 팁의 성능을 최적화하는 데 도움이 할 수있는 코드를 요약 할 수 있습니다 : (당신이 정말 필요로하는 경우 다른 코드가 실행되기 전에, 다음 적어도이 일을) 프로토 타입을 조작하지 마십시오.

번역기의 노트

이 문서는 크게 두 가지로 나눌 수 있습니다.

첫 번째 부분은 JS 엔진은 모든 코드를 최적화하지 않는 이유를 우리에게 설명하고, 왜 각 JS 엔진 디자인은 뭔가 다른 것입니다. 이 지식은 번역자에 대한 몇 가지 더 흥미로운 관점입니다.

  1. V8 인터프리터는 가장 효율적입니다.
  2. 동시 이점을 적용하는 방법의 포인트의 최적화.
  3. 그 코드는 종종 엔진을 최적화하고 더 많은 기회를 실행하기 때문에 설계 및 계획 논리 프로그래밍을 할 수있다.

몇 가지 간단한 경우에 특정 행동을 통해 엔진의 두 번째 부분은, 프로토 타입 체인을 최적화하는 방법을 방문하는 동안 우리에게 엔진을 보여줍니다. 가장 중요한 것은, 이러한 최적화는 특정 가정 장면에 따라 설립을 기반으로, 그래서 당신은 당신의 코드를보다 효율적으로 실행하려는 경우, 이러한 가정에 따라 좋은 코딩 관행을 유지하기 위해 시도하십시오.

이 구문이 아니라 프로토 타입 체인을 가득 클래스, 또한 더 읽기 쉬운 구문은, 모든 사람들이 사용하는 것이 좋습니다.

동적 언어와 JS는 매우 유연합니다,하지만 때로는 성능의 비용이 유연성을 제공합니다. 당신은 런타임 성능에 대해 걱정하는 경우, 자제하시기 바랍니다 무료가 아닌 프로토 타입 체인의 내용을 수정할 수 있습니다.

끝은 당신에게 여러분의 관객 감사합니다.

추천

출처www.cnblogs.com/qianduanwriter/p/11784313.html