본문으로 건너뛰기

V8 릴리즈 v8.0

· 약 5분
본명 V8th Leszek Swirski

드디어 여기에 왔습니다. V8의 모든 릴리즈, 우리의 릴리즈 프로세스의 일환으로, 6주마다 브랜칭할 때마다 V8이 버전 8에 도달할 때 어떤 일이 일어날지에 대한 질문이 등장합니다. 우리가 파티를 열 건가요? 새로운 컴파일러를 출시할 건가요? 우리는 버전 8과 9를 건너뛰고 영원히 V8 버전 X에 머무를 건가요? 10년 이상의 작업 끝에 결국, 100번째 블로그 게시물에서 우리는 가장 새로운 브랜치 V8 버전 8.0 V8을 발표하게 되어 나만의 질문에 답할 수 있게 되어 기쁩니다:

버그 수정 및 성능 개선입니다.

이 게시물은 몇 주 후에 Chrome 80 안정 릴리즈와 조정하여 출시를 예고하는 몇 가지 주요 사항에 대한 미리보기를 제공합니다.

성능 (크기 & 속도)

포인터 압축

모든 void *pv로 변경하여 소스 파일 크기를 최대 66%까지 줄였습니다.

V8 힙은 부동 소수점 값, 문자열 문자, 컴파일된 코드, 태그값(이는 V8 힙 또는 작은 정수를 나타냄) 등 다양한 항목으로 구성되어 있습니다. 힙을 검사한 결과, 이러한 태그값이 힙의 대부분을 차지하는 것으로 나타났습니다!

태그값은 시스템 포인터만큼 크며, 32비트 아키텍처에서는 32비트, 64비트 아키텍처에서는 64비트입니다. 32비트 버전과 64비트 버전을 비교할 때, 모든 태그값에 대해 두 배의 힙 메모리를 사용하고 있습니다.

다행히도 상위 비트를 하위 비트에서 합성할 수 있는 비법이 있습니다. 따라서 우리는 힙에 고유한 하위 비트만 저장하여 귀중한 메모리 자원을 절약할 수 있습니다... 평균적으로 힙 메모리의 40%를 절약할 수 있습니다!

포인터 압축으로 메모리를 평균적으로 40% 절약했습니다.

종종 메모리를 개선하면 성능 감소가 나타납니다. 보통은 그렇죠. 그러나 이번에는 실제 웹사이트에서 V8에 소요된 시간과 쓰레기 수집기에서 성능 개선을 확인했습니다!

데스크톱모바일
FacebookV8-전체-8%-6%
^^GC-10%-17%
CNNV8-전체-3%-8%
^^GC-14%-20%
Google 지도V8-전체-4%-6%
^^GC-7%-12%

포인터 압축에 관심이 있다면, 더 자세한 정보를 제공하는 전체 블로그 게시물을 주목해주세요.

고차 함수 내장 최적화

우리는 최근 TurboFan의 최적화 파이프라인에서 고차 함수 내장의 공격적인 최적화를 방해하던 제한 사항을 제거했습니다.

const charCodeAt = Function.prototype.call.bind(String.prototype.charCodeAt);

charCodeAt(string, 8);

지금까지 charCodeAt 호출은 TurboFan에게 완전히 불투명해 보였고 사용자가 정의한 함수에 대한 일반 호출을 생성했습니다. 그러나 이번 변경으로 우리는 실제로 빌트인의 String.prototype.charCodeAt 함수를 호출하고 있다는 것을 인식할 수 있으며, 따라서 TurboFan이 내장 호출을 개선하기 위해 준비된 모든 추가 최적화를 트리거할 수 있습니다. 이로 인해 다음과 동일한 성능을 얻게 됩니다:

string.charCodeAt(8);

이 변경은 Function.prototype.apply, Reflect.applyArray.prototype.map과 같은 많은 고차 배열 빌트인에도 영향을 미칩니다.

자바스크립트

선택적 체이닝

속성 접근 체인을 작성할 때 프로그래머는 중간 값이 nullish(즉, null 또는 undefined)인지 확인해야 할 때가 많습니다. 오류 확인 없는 체인은 오류를 던질 수 있고, 명시적인 오류 확인을 포함한 체인은 번거롭고 비nullish 값 대신 모든 truthy 값들을 확인해야 하는 부작용이 있습니다.

// 오류가 발생할 가능성이 있는 버전.
const nameLength = db.user.name.length;

// 덜 오류가 발생하지만 읽기 어려움.
let nameLength;
if (db && db.user && db.user.name) nameLength = db.user.name.length;

선택적 체이닝 (?.)을 통해 프로그래머는 중간 값이 nullish인지 체크하는 더 간결하고 견고한 속성 접근 체인을 작성할 수 있습니다. 중간 값이 nullish인 경우, 전체 표현식은 undefined로 평가됩니다.

// 여전히 오류를 확인하며 훨씬 더 읽기 쉽습니다.
const nameLength = db?.user?.name?.length;

정적 속성 접근 외에도 동적 속성 접근 및 호출도 지원됩니다. 자세한 정보와 추가 예제는 우리의 기능 설명서를 참조하세요.

널 병합 연산자

널 병합 연산자 ??는 기본 값을 처리하기 위한 새로운 단축 평가 이항 연산자입니다. 현재 기본 값 처리는 종종 논리 || 연산자를 사용하여 처리됩니다. 아래 예제를 참조하세요.

function Component(props) {
const enable = props.enabled || true;
// …
}

|| 연산자를 사용하는 것은 기본 값을 계산하는 데 바람직하지 않습니다. 왜냐하면 a || ba가 falsy일 때 b를 반환하기 때문입니다. 만약 props.enabled가 명시적으로 false로 설정되어 있다면, enable은 여전히 true가 될 것입니다.

널 병합 연산자를 사용하면 a ?? ba가 널(null 또는 undefined)일 때 b를 반환하고, 그렇지 않으면 a를 반환합니다. 이것이 원하는 기본 값 동작이며, 위의 예제를 ??를 사용해 다시 작성하면 이 버그가 수정됩니다.

function Component(props) {
const enable = props.enabled ?? true;
// …
}

널 병합 연산자와 선택적 체이닝은 보완적인 기능이며 함께 잘 작동합니다. 예제는 props 인수가 전달되지 않았을 때도 처리하도록 수정될 수 있습니다.

function Component(props) {
const enable = props?.enabled ?? true;
// …
}

자세한 정보와 추가 예제는 우리의 기능 설명서를 참조하세요.

V8 API

git log branch-heads/7.9..branch-heads/8.0 include/v8.h를 사용하여 API 변경 사항 목록을 얻을 수 있습니다.

활성 V8 체크아웃을 가진 개발자는 git checkout -b 8.0 -t branch-heads/8.0를 사용하여 V8 v8.0의 새로운 기능을 실험해 볼 수 있습니다. 또는 Chrome의 베타 채널 구독을 통해 곧 새로운 기능을 직접 테스트할 수 있습니다.