【问题标题】:What makes the Java compiler so fast?是什么让 Java 编译器如此之快?
【发布时间】:2010-09-29 00:19:10
【问题描述】:

我想知道是什么让初级 Java 编译器(sun 的 javac)编译速度如此之快?

..以及来自 Microsoft 的 C# .NET 编译器。

我正在将它们与 C++ 编译器(例如 G++)进行比较,所以也许我的问题应该是,是什么让 C++ 编译器如此缓慢:)

【问题讨论】:

  • 你在比较什么?从源代码编译应用程序所需的时间,或运行时性能?
  • 如果有一些例子会更有趣。一些时间测量 + 代码行数。
  • 我比较的是编译时间,不是运行时间。
  • stackoverflow.com/questions/318398/… 不确定这个问题是否应该作为重复问题关闭,所以现在只发布链接。 :)

标签: c# java .net c++ compiler-construction


【解决方案1】:

这个问题在这个问题中得到了很好的回答:Why does C++ compilation take so long?(正如 jalf 在 cmets 部分中指出的那样)

基本上这是 C++ 缺少模块的概念,以及编译器进行的积极优化。

【讨论】:

  • 当然,C# 和 Java 只完成了它们编译为 ByteCode 的一半工作,并停止将其余工作留给代码运行时。 C++ 一次完成所有事情。其他因素,例如 C++ 在每次编译时使用基于文本的巨大头文件也无济于事。
【解决方案2】:

我认为最困难的部分不是需要编译头文件(除非它们真的很大,但在这种情况下你可以使用预编译的头文件)。最糟糕的部分始终是 C++ 的语法对上下文过于敏感。尽管我喜欢 C++,但我为那些不得不写 C++ 解析器的人感到抱歉。

【讨论】:

  • 别担心 - 全世界大约有 10-20 人 :)
【解决方案3】:

有几件事使 C++ 编译器比 Java/C# 的编译器慢。语法要复杂得多,通用编程支持在 C++ 中要强大得多,但同时编译成本更高。包含文件的工作方式与导入模块不同。

包含头文件

首先,每当你在 C++ 中包含一个文件时,文件的内容(通常是 .h)都会被注入到当前编译单元中(包含保护避免重复注入相同的头文件两次),这是传递性的。也就是说,如果您包含头文件 a.h,而头文件又包含 b.h,那么您的编译单元将包含 a.h 中的所有代码和 b.h 中的所有代码。

Java(或C#,我将讨论Java,但它们在这方面是相似的)没有包含文件,它们依赖于所用类编译的二进制文件。这意味着每当你编译使用b.java中定义的对象B的a.java时,它只是检查二进制b.class,它不需要更深入地检查B的依赖关系,所以它可以更早地切断过程(只有一级检查)。

同时,包含文件只包含语言定义,处理需要时间。当 Java/C# 编译器读取二进制文件时,它具有相同的信息,但已由生成它的编译步骤处理。

所以最后,在 C/C++ 中包含更多文件,同时处理这些包含比处理二进制模块更昂贵。

模板

模板有其独特之处。它们可以被预编译,但通常不是(有很多原因)。这意味着在所有使用 std::vector 的编译单元中,使用的整个向量方法集(未使用的模板方法不会被编译)被处理,并且编译器生成二进制代码。在稍后的步骤中,在链接期间,相同方法的冗余定义将被删除,但在编译期间必须对其进行处理。

Java 对泛型的支持在很多方面都受到更多限制。最后,例如,只有一个 Vector 类二进制文件,每当编译器在 java 中看到 Vector 时,它所做的就是在委托给真正的 Vector 实现(存储普通对象)之前生成类型检查代码,这不是通用的。编译器确实提供类型保证,但不会为每种类型编译 Vector。

在 C# 中,这又是不同的。 C# 对泛型的支持比 Java 更复杂,最终泛型类与普通类不同,但无论如何它们只编译一次,因为二进制格式包含所有必需的信息。

【讨论】:

    【解决方案4】:

    因为它们做了一些完全不同的事情,C++ 编译器生成优化的本机代码,而 C#、VB .Net 和 Java 编译器生成的中间语言,而不是当您第一次执行应用程序时转换为本机代码,这就是加载缓慢的原因第一次执行应用程序时使用 Java 等应用程序。

    当您执行应用程序时,C++ 编译器必须对 JITed 语言进行优化的地方进行全面优化。

    有人会争辩说,如果你想正确的话,你必须测量 C++ 编译时间 = Java 编译时间 + 首次加载应用程序时的 JIT 时间,但我认为这不是正确和公平的,因为你正在将母语与 JITed 进行比较,或者将橘子与苹果进行比较。

    【讨论】:

    • C# 编译 + ngen = C++ 编译。 ngen 很快。
    【解决方案5】:

    C++ 编译器必须反复编译所有的头文件,而且头文件很多,所以这是一件拖慢它的事情。

    【讨论】:

    【解决方案6】:

    编译时比较耗时的任务之一是代码优化。

    Javac 在编译时对代码做的优化很少。运行应用程序时由 JVM 进行优化。

    编译时需要优化 C/C++,因为编译的机器代码很难优化。

    【讨论】:

      【解决方案7】:

      你最后一句话说对了:不是 java 或 C# 编译速度快,而是 C++ 编译速度特别慢,因为它的语法和特性很复杂,最重要的是 templates

      【讨论】:

        【解决方案8】:

        如果你认为 javac 很快,试试 Jikes....(见 http://jikes.sourceforge.net/) 它是一个用 C++ 编写的 Java 编译器。不幸的是,他们没有跟上最新的 Java 编译器规范,但如果您想快速了解,就是这样。

        托尼

        【讨论】:

          【解决方案9】:

          我认为部分原因是语言的复杂性。 C++ 具有难以置信的可变性,能够覆盖几乎任何运算符或语法(例如覆盖 () 运算符)。这意味着编译器必须做很多更多的工作来确定实际运行的操作,即使是简单的事情。 Java 和 C# 没有这个问题,因为语法是固定的,而且它们通常更易于解析。

          【讨论】:

            【解决方案10】:

            比较像 java 这样的字节码语言和像 C++ 这样的本地编译语言有点困难。更好的比较是 Delphi 与 C++,其中 Delphi 的编译速度要快得多。由于这与优化或字节码无关,因此一定是由于语言语法的差异以及包含与模块/单元的相对性能。

            【讨论】:

              【解决方案11】:

              Java 编译器快吗?

              Java 到类的转换应该非常快,因为它只是一个带有一些语法检查的美化 zip,所以如果与进行优化和目标代码生成的真正编译器相比,从 Java 到类的“转换”是公平的微不足道。

              与相当小的程序“hello world”进行比较,并与 GCC (C/C++/Ada) 进行比较,发现 javac 慢了 30 倍,并且在运行时变得更糟?

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2011-10-07
                • 2020-08-29
                • 2023-03-31
                • 2010-10-16
                • 1970-01-01
                相关资源
                最近更新 更多