12

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

我的理解是,这些语言是机器代码的抽象,它们最终都编译成这样。处理器不应该决定性能吗?

4

5 回答 5

8

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

除此之外,C++ 模板比 Java 或 C# 泛型更易于优化。尽管 JIT 经常因其跨模块边界优化的能力而受到称赞,但泛型阻止了这种死循环。CLR(.NET 运行时)只为涵盖所有引用类型的泛型生成一个版本的机器代码。另一方面,C++ 优化器针对模板参数的每个组合运行,并且可以内联相关调用。

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

于 2011-10-03T17:28:40.477 回答
6

考虑语言的差异以及由此产生的开销——即使这些额外的工作“以相同的效率”完成,也还有更多工作要做。时期。(这是抽象经常带来的代价:开发时间可以[大幅]减少,因为[适度]增加运行时间。)

另一方面,使用不使用“语言特征”的微不足道的函数,例如计算阶乘的循环......那么在某些情况下,这些数字会变得非常有竞争力。这可以在The Computer Language Benchmark Game中看到(例如,这里是Java7 vs. C++)。

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

快乐编码。


正如Been Voigt 所指出的,JIT/AOT 模型针对不同方面进行了优化。(这太阳Oracle Java 实现甚至有一个单独的服务器虚拟机和客户端虚拟机,它们各自优先考虑不同的用例。)以下是一些讨论 JIT 与 AOT 的 SO 帖子:

于 2011-10-03T17:14:17.667 回答
5

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

C# 和Java 都编译为字节码,最终被虚拟机简化为机器码(例如,对于Java,它称为JVM)。然而,C++ 通常最初被编译到汇编级别。

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

于 2011-10-03T17:17:34.637 回答
3

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

花一些时间学习如何反汇编您编译的二进制文件。阅读 java、python 等背后的字节码类型指令集。pascal 曾经使用的 p-code 等。

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

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

于 2011-10-04T21:16:41.503 回答
2

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

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

稍有不同,请理解,您在网络上看到的许多关于性能的声明都是错误的,而且您在网络上看到的许多性能测量已经过时或不可靠或以其他方式损坏。

例如,phresnel 指出了一个微小的乘法程序的测量值,这些测量值是:

  • 早在 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 完成编译后,时间从 4609 毫秒降至 563 毫秒。

Java 代码的速度比您认为的简单测量要快 8 倍。

于 2011-10-16T17:04:16.077 回答