V8

V8에 사전 컴파일 힌트 제공: 명시적 컴파일 힌트로 JavaScript 시작 속도 향상

원문은 CC-BY-3.0
라이선스로 제공되며, 이 글은 한국어로 번역한 2차 저작물입니다.
빠른 JavaScript 실행은 반응형 웹 앱의 핵심입니다. V8의 고급 최적화 기능에도 불구하고, 시작 시점에 중요한 JavaScript를 파싱하고 컴파일하는 것은 여전히 성능 병목 현상을 유발할 수 있습니다. 초기 스크립트 컴파일 중에 어떤 JavaScript 함수를 컴파일할지 미리 알면 웹 페이지 로딩 속도를 높일 수 있습니다.
네트워크에서 로드된 스크립트를 처리할 때, V8은 각 함수에 대해 즉시 컴파일("eagerly")할지 또는 이 프로세스를 연기할지 결정해야 합니다. 아직 컴파일되지 않은 함수가 나중에 호출되면, V8은 필요에 따라 즉시 컴파일해야 합니다.
JavaScript 함수가 페이지 로드 중에 호출되는 경우, 해당 함수를 즉시 컴파일하는 것이 유리합니다. 그 이유는 다음과 같습니다.
  • 스크립트의 초기 처리 중에 함수 끝을 찾기 위해 최소한 경량 파싱(lightweight parse)을 수행해야 합니다. JavaScript에서는 함수 끝을 찾는 데 전체 구문을 파싱해야 합니다 (중괄호 개수만으로 알 수 있는 지름길은 없습니다. 문법이 너무 복잡하기 때문입니다). 먼저 경량 파싱을 수행하고 나중에 실제 파싱을 수행하는 것은 중복 작업입니다.
  • 함수를 즉시 컴파일하기로 결정하면, 해당 작업은 백그라운드 스레드에서 수행되며, 네트워크에서 스크립트를 로드하는 작업과 일부 작업이 교차적으로 실행됩니다. 대신 함수가 호출될 때만 컴파일하기로 하면, 메인 스레드는 함수가 컴파일될 때까지 진행할 수 없으므로 작업을 병렬화하기에는 너무 늦습니다.
V8이 JavaScript를 파싱하고 컴파일하는 방법에 대해 더 자세히 알아보려면 여기
를 참조하세요.
많은 웹 페이지에서 즉시 컴파일을 위해 올바른 함수를 선택하면 이점을 얻을 수 있습니다. 예를 들어, 인기 있는 웹 페이지를 대상으로 한 실험에서 20개 중 17개 페이지에서 성능이 향상되었으며, 평균 포그라운드 파싱 및 컴파일 시간 감소는 630ms였습니다.
저희는 웹 개발자가 어떤 JavaScript 파일과 함수가 즉시 컴파일될지 제어할 수 있도록 하는 기능인 Explicit Compile Hints
를 개발하고 있습니다. Chrome 136부터는 개별 파일을 즉시 컴파일하도록 선택할 수 있는 버전이 출시되었습니다.
이 버전은 "핵심 파일(core file)"이 있어 즉시 컴파일을 선택하거나, 이러한 핵심 파일을 만들기 위해 소스 파일 간에 코드를 이동할 수 있는 경우 특히 유용합니다.
파일 상단에 다음 매직 주석을 삽입하여 전체 파일에 대해 즉시 컴파일을 트리거할 수 있습니다.
//# allFunctionsCalledOnLoad
하지만 이 기능은 신중하게 사용해야 합니다. 너무 많이 컴파일하면 시간과 메모리를 소비하게 됩니다!

직접 확인해보세요 - 컴파일 힌트 작동 방식

함수 이벤트를 기록하도록 v8에 지시하여 컴파일 힌트가 작동하는 것을 관찰할 수 있습니다. 예를 들어, 최소한의 테스트를 설정하기 위해 다음 파일을 사용할 수 있습니다.
index.html:
<script src="script1.js"></script><script src="script2.js"></script>
script1.js:
function testfunc1() {  console.log('testfunc1 called!');}testfunc1();
script2.js:
//# allFunctionsCalledOnLoadfunction testfunc2() {  console.log('testfunc2 called!');}testfunc2();
코드 캐싱이 실험에 영향을 미치지 않도록 Chrome을 깨끗한 사용자 데이터 디렉토리로 실행해야 합니다. 예시 명령줄은 다음과 같습니다.
rm -rf /tmp/chromedata && google-chrome --no-first-run --user-data-dir=/tmp/chromedata --js-flags=--log-function_events > log.txt
테스트 페이지로 이동한 후 로그에서 다음과 같은 함수 이벤트를 볼 수 있습니다.
$ grep testfunc log.txtfunction,preparse-no-resolution,5,18,60,0.036,179993,testfunc1function,full-parse,5,18,60,0.003,181178,testfunc1function,parse-function,5,18,60,0.014,181186,testfunc1function,interpreter,5,18,60,0.005,181205,testfunc1function,full-parse,6,48,90,0.005,184024,testfunc2function,interpreter,6,48,90,0.005,184822,testfunc2
testfunc1
은 지연 컴파일되었으므로, 결국 호출될 때
parse-function
이벤트를 볼 수 있습니다.
function,parse-function,5,18,60,0.014,181186,testfunc1
testfunc2
의 경우, 컴파일 힌트가 즉시 파싱 및 컴파일을 강제했기 때문에 해당 이벤트가 보이지 않습니다.

Explicit Compile Hints의 미래

장기적으로는 개별 함수를 즉시 컴파일 대상으로 지정하는 방향으로 나아가고자 합니다. 이를 통해 웹 개발자는 컴파일할 함수를 정확하게 제어하고, 컴파일 성능의 마지막 부분을 짜내어 웹 페이지를 최적화할 수 있습니다. 계속 지켜봐 주세요!