If C#, Java, or C++, for example, all eventually compile to machine
code, why are they not equally performant?
Most simply - they don't all compile to the same machine code.
On a slightly different note, please understand that a lot of the claims about performance you'll see on the web will be wrong, and a lot of the measurements of performance you'll see on the web are out-of-date or unreliable or broken in some other way.
For example, phresnel pointed to measurements of a tiny multiplication program, and those measurements were:
Let's just run his program half-a-dozen times without re-starting the JVM and see what happens:
public class mult {
public static void main(String[] args){
for (int i=0; i<6; ++i) mult.program_main(args);
}
public static void program_main(String[] args) {
long nbStep = 1000000000;
long tCPU = System.currentTimeMillis();
double t=1. , r= 0.9999999999999999999999999999999999;
if ( args.length > 0 ) {
nbStep = Integer.parseInt(args[0]);
System.out.println( args[0] + " demandees" );
}
for ( long i = 0; i < nbStep; i++ ) {
t = t * r;
}
tCPU = - tCPU + System.currentTimeMillis();
System.out.println(nbStep + " multiplications en " +
tCPU + " millisecondes ." );
}
}
$ /usr/local/src/jdk1.7.0/bin/java -XX:+PrintCompilation -XX:+PrintGC mult
53 1 % mult::program_main @ 57 (122 bytes)
4662 1 % mult::program_main @ -2 (122 bytes) made not entrant
1000000000 multiplications en 4609 millisecondes .
4662 1 mult::program_main (122 bytes)
4669 2 % mult::program_main @ 57 (122 bytes)
1000000000 multiplications en 4612 millisecondes .
1000000000 multiplications en 564 millisecondes .
1000000000 multiplications en 563 millisecondes .
1000000000 multiplications en 563 millisecondes .
1000000000 multiplications en 563 millisecondes .
Once Java completes compilation the times drop from 4609ms to 563ms.
The Java code is 8 times faster than the naïve measurement would have you believe.