-
V8엔진을 통한 효율적인 JS개발프로그래밍 2018. 11. 14. 01:49
안녕하세요 오늘은 지난 시간에 알아봤던 V8엔진을 이용해 어떻게 Js코드를 작성해야 더 효율적일지 알아보는 시간을 가져보도록하겠습니다
V8이 무엇인지 헷갈리시는 분들은 http://dayzen1258.tistory.com/entry/V8%EC%97%94%EC%A7%84%EC%9D%B4%EB%9E%80에 들어가서 확인해주세요~
그렇다면 어떻게 해야 효율적인 코드를 작성할수있을까요?
지난 시간에 알아봤던 봤던 크랭크샤프트에서 최적화를 하는 방식을 본다면 알수있습니다
바로 인라인캐싱과 히든 클래스가 추가로 인라이닝이 이번 시간에 주요하게 살펴볼 내용입니다
인라인 캐싱
인라이닝이라는 용어에 대하여 간단히 설명하자면 함수가 호출되는 부분의 코드를 함수의 내용으로 변경한다고 보시면됩니다
예제를 들어 설명을 하자면 다음과 같습니다
function a(){
const a = test1(1);
const b = test2(2);
return a + b;
}
라는 위의 a라는 메소드가 있다고 보면 test1과 test2를 호출합니다 test1, test2메소드는 다음과 같은데
function test1(num){
return num * 2;
}
function test2(num){return num + 2;
}
즉 a 메소드는 인라이닝을 적용하면 다음과 같아집니다
function a(){
const a = 1 * 2;
const b = 2 + 2;
return a + b;
}
왜 위와 같이 변환하는 작업이 최적화에 영향을 끼칠까요?
먼저 함수를 호출하는 코스트는 많이 듭니다 생각해봐도 함수를 호출하려면 그 함수가 어디에있는지 검사를 해야하기에 본문 내용으로 함수를 옮겨둔다면 함수의 위치 자체를 찾을 필요가 없어져 효율적이게 되는것입니다
히든 클래스
Js는 프로토 타입 기반의 언어입니다 객체라고 해도 결국 __proto__로 체이닝 연결이되어서 사용이되죠
대부분의 Js인터프리터는 자료구조 Set을 보신다고 보시면 될것 같습니다
Js는 상속하는 객체의 프로퍼티가 항상 동적으로 변경이 가능하기에 대부분의 컴파일전에 객체의 주소를 알고 {"객체의 주소": 객체 } 이런식의 딕셔너리로 저장이 Js에서는 불가합니다
그렇기에 Js에서 위와같은 방식으로 처리하면 굉장히 비효율적입니다 그렇기에 V8에서는 새로운 개념인 히든클래스라는 개념을 사용하는데
먼저 간단히 히든클래스의 정의를 보면 다음과 같습니다
'하나의 객체는 하나의 히든클래스의 주소를가진다'라고 보시면 될것같은데 예시를 들어 설명하겠습니다
function Point(x, y) {
this.x = x;
this.y = y;
}
const p = new Point(1,2);
ES6 전에 흔히 사용되던 객체 생성 코드입니다 여기서 new Point(1,2)라는 코드가 실행되면 다음과 같은 상황이 발생합니다
Point에는 아무런 설정도 되어있지 않기에 C0이라는 비어있는 히든클래스가 생성이됩니다
그 뒤에 this.x = x라는 코드가 실행되면 다음과 같아집니다
x에 해당하는 또다른 히든클래스 C1이 만들어지게 됩니다
왜 히든 클래스가 중요하냐면 Java와 같은 객체가 컴파일 되고난후에는 객체 속성이 바뀔수가없어 메모리에 고정적으로 들어가는데
Js는 런타임에도 동적으로 추가가 되기에 히든클래스를 이용해서 동일한 객체로 들어오는경우에는 히든클래스에서 찾아 공용으로 사용이 가능하기에 중요합니다
this.y = y코드가 실행되었을 경우에는 다음과 같이 변경됩니다
어떤 개념인지 감이 잡히시나요?
하지만 여기서 중요한점은!! 히든 클래스의 변경은 순서에 의존합니다
다음과 같은 코드를 보시죠
function Point(x, y) {
this.x = x;
this.y = y;
}
const p1 = new Point(1,2);
p1.t = 3;
p1.tt = 4;
const p2 = new Point(1,2);
p2.tt = 5;
p2.t = 6;
위의 p1과 p2는 히든클래스를 공유할것이라고 예상하지만 실제로는 두개의 별개의 히든클래스를 만들어낸 개념입니다
p1은 t -> tt, p2는 tt -> t의 순서로 만들기에 두개의 다른 히든 클래스가 만들어지는것이죠
그렇기에 객체의 요소 추가 순서를 맞춘다면 히든클래스의 무분별한 생성을 막고 공용으로 사용이 가능합니다
그렇다면 이제 인라인 캐싱이란 무엇인가에 대해서 알아보도록하겠습니다
Js를 머신 코드로 변환하면서 해당 객체의 타입을 알수가있습니다 그럼 해당 객체는 따로 머신코드로 변환하지않고 기존에 머신코드로 변환해놓은 코드를 이용합니다
즉 간단히 예시를 들어보자면
function Point(x, y) {
this.x = x;
this.y = y;
}
const a = new Point(1,2) // V8엔진에서 머신코드로 변환한뒤 그 데이터를 저장
const b = new Point(3,5) // 이미 동일한 Type의 객체를 머신코드로 변환한적이 있기에 기존의 머신코드를 이용
위와 같은 방식으로 진행됩니다
그렇지만 캐싱이라는 말이 들어간 모든 개념과 비슷하게 Type이 달라지면 기존의 캐시한 데이터는 사용하지 못합니다
그렇기에 히든클래스가 존재하지않는다면 다시 위와같은 반복작업을 돌리고 히든클래스를 저장 해놓은뒤 다음에 같은 타입으로 변환할경우 기존의 머신코드를 주는 방식입니다
어떤 개념인지 이해가 가셨나요?
실제로 저도 공부를 하면서 적은 내용이라 어렵기는 마찬가지였습니다...
읽어보시면서 이해가 안되는 부분이나 잘못된 부분을 알려주시면 정말 감사하겠습니다 :)
'프로그래밍' 카테고리의 다른 글
자바스크립트 메모리 누수와 어떻게 막아야 하는가? (1) 2018.11.19 자바스크립트의 메모리 관리법 (0) 2018.11.15 V8엔진이란? (0) 2018.11.13 자료형의 범위에 대하여 (0) 2018.06.17 함수형 프로그래밍? (0) 2018.04.23