如果编译语言最终成为机器代码,为什么它们不能同等地执行?

时间:2011-10-03 17:07:56

标签: performance programming-languages machine-code

例如,如果C#,Java或C ++都编译为机器代码,为什么它们的性能不同呢?

我的理解是这些语言是机器代码的抽象,这是他们最终编译的内容。处理器不应该确定性能吗?

5 个答案:

答案 0 :(得分:8)

首先,C ++优化器更加成熟。另一方面,性能一直是C ++语言设计者的首要目标(“你不为你不使用的东西买单”是口头禅,显然不能说Java的每个方法都是虚拟的政策)。

除此之外,C ++模板比Java或C#泛型更加优化。虽然JIT经常因其跨模块边界进行优化的能力而受到称赞,但是仿制药可以阻止这种死亡。 CLR(.NET运行时)仅为通用生成一个版本的机器代码,涵盖所有引用类型。另一方面,C ++优化器针对模板参数的每个组合运行,并且可以内联依赖调用。

接下来,使用C#和Java,您几乎无法控制内存布局。并行算法可能会因缓存行的错误共享而遭受一个数量级的性能下降,并且开发人员几乎不会对此做任何事情。 OTOH C ++提供了将对象放置在相对于RAM页面和缓存边界的特定偏移处的工具。

答案 1 :(得分:6)

考虑语言的差异和发生的开销 - 即使这样的额外工作“以相同的效率”完成,还有更多工作要做。期。 (这是抽象通常带来的代价:开发时间可以[基本]减少运行时间的[适度]增加。)

另一方面,使用没有“语言特征”的简单函数,例如计算因子的循环......那么在某些情况下数字可以变得非常有竞争力。这可以在The Computer Language Benchmark Game中找到(例如,此处为Java7 vs. C++)。

请注意,应用语言(包括JIT)和优化(“-Ox”)的实现也是一个主要因素。 (一种语言本身就可以说“没有速度”。)

快乐的编码。


正如Voigt所指出的那样,JIT / AOT模型针对不同方面进行了优化。 ( Sun Oracle Java实现甚至有一个单独的服务器VM和客户端VM,每个VM都优先考虑不同的用例。)以下是一些讨论JIT与AOT的SO帖子:

答案 2 :(得分:5)

“例如,如果C#,Java或C ++最终都编译成机器代码,为什么它们的性能不同?”

C#和Java都编译成字节码,最终由虚拟机(例如Java称为JVM)缩减为机器码。但是,C ++通常最初编译为汇编级别。

虚拟机实际上可以在运行时执行某些优化(一个常见的例子是双态内联),但在其他情况下,增加的开销会对性能产生负面影响

答案 3 :(得分:3)

您是否知道相同的C ++代码不会使用不同的编译器或相同编译器的不同版本生成相同的机器代码?一些编译器将使用相同的源并为同一目标创建二进制文件,这比另一个编译器快得多。出于同样的原因,编译为机器代码的其他语言将不会执行相同的操作。有些语言比其他语言更容易编译/优化。像Java这样的语言没有比较,因为它们没有编译成通常编译为系统无关字节码的机器代码,然后在虚拟机jvm上运行。 jvm是由某些编译器编译的某些语言的代码,根据所选的代码和编译器,它可以快速或慢速。与直接编译到机器代码相比,像java(字节码)这样的解释语言很慢。

花些时间学习如何反汇编已编译的二进制文件。阅读java,python等背后的字节码类型指令集,以及pascal过去常用的p代码等。

如果您正在谈论x86计算机,那么您在该系列中的性能差异很大。您可以在一个x86处理器上编译相对于时钟速率运行速度非常快的二进制文件,但是相同的二进制文件在另一个上运行速度非常慢,通常具有更快时钟速率的较新处理器运行较旧的二进制文件较慢。在x86世界中,创建一个可以在任何地方快速运行的单个二进制文件是徒劳的,因此如果需要性能,您的编译器必须更加努力地尝试针对每个系统/处理器的性能。

你的问题类似于询问,如果所有车辆基本上都有一个发动机和四个轮子,为什么有些车会更快?为什么有些人会比其他人更多的东西?

答案 4 :(得分:2)

  

例如,如果C#,Java或C ++最终都编译为机器   代码,为什么它们的表现不同?

最简单 - 它们并非都编译为相同的机器代码。

稍微不同的是,请理解您在网络上看到的很多关于性能的说法都是错误的,而且您在网上看到的很多性能测量结果都是不合适的。以某种其他方式约会或不可靠或破裂。

例如,phresnel指的是a tiny multiplication program的测量值,这些测量值是:

  • 2003年用Java 1.4制作 - 当前版本是Java 7

  • 以一种非常天真的方式制作,阻止Java完成 汇编

让我们在没有重新启动JVM的情况下运行他的程序六次,看看会发生什么:

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 .

Java完成编译后,时间从4609ms下降到563ms。

Java代码比你想象的天真测量<8>快