첫째, 대부분의 JVM에는 컴파일러가 포함되어 있으므로 "해석 된 바이트 코드"는 실제로는 거의 드물다 (적어도 벤치 마크 코드에서는 실제로는 드물지 않다). ).
둘째, 관련 벤치 마크의 상당수가 상당히 편향되어있는 것으로 보입니다 (의도 나 무능함에 따라 실제로 말할 수는 없습니다). 예를 들어, 몇 년 전에 게시 한 링크 중 하나에서 링크 된 소스 코드 중 일부를 살펴 보았습니다. 다음과 같은 코드가 있습니다.
init0 = (int*)calloc(max_x,sizeof(int));
init1 = (int*)calloc(max_x,sizeof(int));
init2 = (int*)calloc(max_x,sizeof(int));
for (x=0; x<max_x; x++) {
init2[x] = 0;
init1[x] = 0;
init0[x] = 0;
}
calloc
이미 제로화 된 메모리를 제공 하므로 for
루프를 다시 제로화하는 것은 쓸모가 없습니다. 어쨌든 다른 데이터로 메모리를 채우고 (제로화되는 것에 의존하지 않음) 메모리가 제공되면 모든 제로화는 완전히 불필요합니다. 위의 코드를 간단한 것으로 교체하면 malloc
(다른 사람이 처음 사용했던 것처럼) C ++ 버전의 속도가 향상되어 Java 버전을 능가 할만큼 (메모리가 제공되는 경우 상당히 넓은 마진으로) 향상되었습니다.
methcall
마지막 링크의 블로그 항목에 사용 된 벤치 마크 를 고려하십시오 (다른 예) . 이름 (및 상황이 어떻게 보일지)에도 불구하고 C ++ 버전은 실제로 메소드 호출 오버 헤드에 대해별로 측정 하지 않습니다 . 중요한 것으로 밝혀진 코드 부분은 Toggle 클래스에 있습니다.
class Toggle {
public:
Toggle(bool start_state) : state(start_state) { }
virtual ~Toggle() { }
bool value() {
return(state);
}
virtual Toggle& activate() {
state = !state;
return(*this);
}
bool state;
};
중요한 부분은로 밝혀졌습니다 state = !state;
. 우리가 같은 상태를 인코딩하기 위해 코드를 변경할 때 발생하는 고려 int
대신의 bool
:
class Toggle {
enum names{ bfalse = -1, btrue = 1};
const static names values[2];
int state;
public:
Toggle(bool start_state) : state(values[start_state])
{ }
virtual ~Toggle() { }
bool value() { return state==btrue; }
virtual Toggle& activate() {
state = -state;
return(*this);
}
};
이 작은 변화는 전체 속도를 약 5 : 1 마진 향상시킵니다 . 벤치 마크가되었다 비록 의도 한 현실에서,이 측정 된 것을 대부분의 메소드 호출 시간을 측정 사이의 변환을 할 수있는 시간이었다 int
및 bool
. 나는 원래의 비 효율성이 불행하다는 것에 분명히 동의하지만, 실제 코드에서 거의 발생하지 않는 것처럼 보이며 그것이 발생할 때 / 고정 될 때 쉽게 고칠 수 있다고 생각하면 어려운 시간을 보내고 있습니다. 그것의 많은 의미로.
누구든지 관련된 벤치 마크를 다시 실행하기로 결정한 경우 Java 버전에 거의 똑같이 수정 된 내용이 있거나 추가로 테스트를 다시 실행하지 않은 Java 버전이 추가되어야한다고 덧붙여 야합니다 최근 JVM은 여전히 확인합니다.) Java 버전도 상당히 향상되었습니다. Java 버전에는 다음과 같은 NthToggle :: activate ()가 있습니다.
public Toggle activate() {
this.counter += 1;
if (this.counter >= this.count_max) {
this.state = !this.state;
this.counter = 0;
}
return(this);
}
this.state
직접 조작하는 대신 기본 함수를 호출하도록 이것을 변경하면 속도가 상당히 향상됩니다 (수정 된 C ++ 버전을 따라갈 수는 없지만).
그래서 우리가 끝내는 것은 해석 된 바이트 코드와 내가 본 최악의 벤치 마크 중 일부에 대한 잘못된 가정입니다. 의미있는 결과를 제공하지도 않습니다.
저 자신의 경험은 동일하게 숙련 된 프로그래머가 최적화에 동일한 관심을 기울이면 C ++이 Java보다 더 자주 이길 수 있지만 (적어도이 둘 사이에서) 언어는 프로그래머와 디자인만큼 큰 차이를 만들지 않습니다. 인용 된 벤치 마크는 벤치마킹하려는 언어에 대한 것보다 저자의 유능함 / 부정직함에 대해 더 많이 알려줍니다.
[편집 : 위의 한 곳에서 암시되었지만 필자가해야 할 것으로 직접 언급하지는 않았지만 인용 한 결과는 ~ 5 년 전에 테스트했을 때 얻은 결과입니다. 현재 당시의 C ++ 및 Java 구현을 사용하여 . 현재 구현으로 테스트를 다시 실행하지 않았습니다. 그러나 한 눈에 코드가 수정되지 않았으므로 코드의 문제를 해결할 수있는 컴파일러의 기능 만 변경 될 것입니다.]
우리는 자바 예제를 무시하면 그러나, 이다 해석 코드 (어렵고 다소 특이한하지만) 컴파일 된 코드보다 빠르게 실행하는 데 실제로 가능합니다.
일반적으로 해석되는 코드는 머신 코드보다 훨씬 간결하거나 코드 캐시보다 데이터 캐시가 더 큰 CPU에서 실행되고 있습니다.
이러한 경우 작은 해석기 (예 : Forth 구현의 내부 해석기)는 코드 캐시에 완전히 들어갈 수 있으며 해석하는 프로그램은 데이터 캐시에 완전히 들어갈 수 있습니다. 캐시는 일반적으로 주 메모리보다 10 배 이상 빠르며 종종 훨씬 더 많습니다 (100 배는 더 이상 드물지 않습니다).
따라서 캐시가 기본 메모리보다 N의 인자만큼 빠르고 각 바이트 코드를 구현하는 데 N 머신 코드 명령보다 적은 시간이 걸리면 바이트 코드가 승리해야합니다 (단순하지만 일반적인 아이디어는 여전히 분명하다).