답변:
JIT 컴파일러는 실행 직전 또는 이미 실행중인 경우에도 즉시 코드를 컴파일합니다. 이런 방식으로 코드가 실행중인 VM은 코드 실행에서 패턴을 확인하여 런타임 정보로만 가능한 최적화를 허용 할 수 있습니다. 또한 VM이 컴파일 된 버전이 어떤 이유로 든 충분하지 않다고 판단하면 (예 : 너무 많은 캐시 누락 또는 특정 예외를 자주 발생시키는 코드) 훨씬 다른 방법으로 다시 컴파일하기로 결정할 수 있습니다. 편집.
반면에 C 및 C ++ 컴파일러는 전통적으로 JIT가 아닙니다. 개발자 컴퓨터에서 한 번만 단일 샷으로 컴파일 한 다음 실행 파일이 생성됩니다.
JIT는 JIT (Just-In-Time) 컴파일러의 약자이며 이름은 잘못되었습니다. 런타임 중에는 가치있는 코드 최적화를 결정하고 적용합니다. 일반적인 컴파일러를 대체하지는 않지만 인터프리터의 일부입니다. 중간 코드를 사용하는 Java 같은 언어는이 점에 유의 모두 : 중간 코드 번역 소스에 대한 일반 컴파일러, 성능 부스트에 대한 인터프리터에 포함 된 JIT.
코드 최적화는 확실히 "클래식"컴파일러에 의해 수행 될 수 있지만 주요 차이점은 JIT 컴파일러가 런타임시 데이터 에 액세스 할 수 있다는 것 입니다. 이것은 큰 장점입니다. 제대로 활용하는 것은 어려울 수 있습니다.
예를 들어 다음과 같은 코드를 고려하십시오.
m(a : String, b : String, k : Int) {
val c : Int;
switch (k) {
case 0 : { c = 7; break; }
...
case 17 : { c = complicatedMethod(k, a+b); break; }
}
return a.length + b.length - c + 2*k;
}
정상적인 컴파일러는 이것에 대해 너무 많은 것을 할 수 없습니다. 그러나 JIT 컴파일러 m
는 k==0
어떤 이유로 만 호출되는 것을 감지 할 수 있습니다 (시간이 지남에 따라 코드가 변경 될 수 있음). 그런 다음 더 작은 버전의 코드를 생성 할 수 있습니다 (그리고 개념적으로 마이너 포인트라고 생각하더라도 네이티브 코드로 컴파일 할 수 있습니다).
m(a : String, b : String) {
return a.length + b.length - 7;
}
이 시점에서 아마도 메소드 호출이 사소한 것처럼 인라인 될 것입니다.
분명히 Sun은 javac
Java 6에서 사용되는 대부분의 최적화를 무시했습니다 . 이러한 최적화로 인해 JIT가 많은 작업을 수행하는 것이 어려워지고 순진하게 컴파일 된 코드가 결국 더 빨리 실행되었다고 들었습니다. 그림을 이동.
m
확인하지 않았다 버전과 k
는 것을 증명 할 수없는 것이기 때문에 m
것이 결코 아닌 0으로 호출 할 수 k
있지만, 심지어 대체 할 수 있음을 입증 할 수없이 그것은 static miss_count; if (k==0) return a.length+b.length-7; else if (miss_count++ < 16) { ... unoptimized code for
m 과 함께 ...} else { ... consider other optimizations...}
.
k=0
always 인 경우에만 테스트를 중단하는 것이 안전합니다. 그러나이를 결정하는 데는 정적 분석이 필요합니다. 이는 매우 비싸고 컴파일 시간에 저렴한 비용입니다. 코드 블록을 통한 하나의 경로가 다른 경로보다 훨씬 더 자주 사용되면 JIT가 이길 수 있으며이 경로에 특화된 코드 버전이 훨씬 빠릅니다. 그러나 JIT는 여전히 빠른 경로가 적용되는지 여부를 확인 하고 그렇지 않은 경우 "느린 경로"를 테스트합니다 .
Base* p
매개 변수를 가져 와서 이를 통해 가상 함수를 호출합니다. 런타임 분석에 따르면 항상 (또는 거의 항상) 가리키는 실제 객체는 Derived1
유형 인 것으로 보입니다 . JIT는 정적으로 해결 된 (또는 심지어 인라인 된) Derived1
메소드 호출로 함수의 새 버전을 생성 할 수 있습니다 . 이 코드 앞에는 p
vtable 포인터가 예상 Derived1
테이블 을 가리키는 지 여부를 확인하는 조건부가 있습니다 . 그렇지 않으면 대신 동적으로 해결되는 느린 메소드 호출로 함수의 원래 버전으로 건너 뜁니다.