【问题标题】:Why is it that bytecode might run faster than native code [closed]为什么字节码可能比本机代码运行得更快[关闭]
【发布时间】:2011-08-04 05:22:03
【问题描述】:

Java 很慢。

这不仅仅是一个“都市传说”,它似乎是一个事实。由于延迟,您不会将其用于实时编码,也不会将其用于集群/并行计算。那里有成千上万的基准测试,特别是“Java vs C# vs C++”。

http://benchmarksgame.alioth.debian.org/

根据上面的网站,不仅 Java 性能几乎与 C 一样好(与其他语言相差甚远),而且 Scala 和 Clojure(都是在 JVM 上运行的函数式语言)都具有比 OCaml、Erlang 更好的性能。

还有很多“Java 比 X 更快”,也有(例如,关于 SO 的问题:Java Runtime Performance Vs Native C / C++ Code?)。

所以在某些情况下,Java 似乎很快。谁能解释一下原因?

在某些情况下,在给定动态代码(Scala、Clojure)和垃圾回收的情况下,为什么字节码可能比本机代码运行得更快?速度快了怎么还有延迟?

这里好像有点矛盾,谁能解释一下?

【问题讨论】:

  • 正确的 GC 肯定比任何非平凡手动内存管理都要快。
  • Java VM 可以使用在应用程序运行期间收集的信息进行优化,而这些信息在编译时是不可用的。
  • 创建一个可管理数量的对象,你不会得到显着的 GC 开销,如果这是一个真正的担忧,但在 90% 以上的情况下它不是。可以构建一个白天根本不进行 GC 的系统。
  • @OscarRyz >>Java VM 可以使用在应用程序运行期间收集的信息进行优化,但在编译时不可用

标签: java performance jvm native-code


【解决方案1】:

JVM 有多种形式!

根据收集的性能特征,最快的将字节码即时编译为本机代码。所有这些都需要额外的内存,因此他们以内存为代价来购买速度。此外,最高速度需要一段时间才能达到,因此短期程序不会显示好处。

即便如此,JamVM 解释器(与 Oracle JVM 相比很小)仍然达到已编译 JVM 的合理部分的最高速度。

关于垃圾回收,速度再次来自有足够的可用内存。真正的好处还来自于从代码中删除了跟踪对象何时不再使用的责任。这会产生更简单、更不容易出错的程序。

【讨论】:

    【解决方案2】:

    这是一个古老的论点。几乎所有流行的 Emacs 和 VI。(但绝对没有那么旧)。我看到很多 c++ 开发人员就为什么大多数性能基准测试(特别是提到 java 与 c++__ 一样快)存在偏差提出了很多论据,老实说,他们说得有道理。

    我没有足够的知识或时间来深入了解 Java 如何能像 C++ 一样快,但以下是它可能的原因......

    1- 当您请两位非常有能力的开发人员用 Java 和 C++ 编写代码来解决现实世界的问题(相同的问题)时,如果 java 的执行速度比 C++ 快,我会感到惊讶。编写良好的 C++ 使用 Java 将使用的一小部分内存。 (Java 对象稍微臃肿一些)。

    2- Java 本质上是一种更简单的语言,它的编写是为了确保难以编写次优代码。通过抽象内存管理以及处理低级优化,用 Java 编写比 C++ 更好的代码更容易。 (我认为这是最重要的事情......很难用 Java 编写糟糕的代码)。另一方面,一个好的 C++ 开发人员可以比 Java 中的自动 GC 更好地处理内存管理。 (Java 将所有内容都存储在堆中,因此会占用更多内存...)

    3- Java 编译器一直在改进,热点之类的想法已被证明比营销术语更好。 (在引入 JIT 时,它只是一个营销术语.. 据我所知.. :))

    4- 人体工程学或根据底层操作系统参数定制设置使 java 处理变化更好。因此,在某些环境中,不难想象 Java 的性能与 C++ 一样好。

    5- 为 Java 开发人员开放高级并发和并行 API 也是一个原因。 Java 并发包可以说是编写可以利用当今多处理器环境的高性能代码的最简单方法。

    6- 随着硬件变得越来越便宜,开发人员的能力已经成为一个更大的因素,这就是为什么我相信很多 c++ 代码可能比 Java 慢。

    【讨论】:

    • 泛型不会在字节码级别移除任何类型转换,并且对性能没有影响。
    • 是的,你是对的。更正了答案。
    【解决方案3】:

    在《编程大师》一书中,James Gosling 解释道:

    詹姆斯:没错。这些天我们 击败真正优秀的 C 和 C++ 编译器几乎总是。当你 去动态编译器,你得到 编译器的两个优点 在最后一刻运行。一 你知道到底是什么芯片组吗 你正在运行。很多时候当 人们正在编译一段 C 代码,他们必须编译它才能运行 在通用 x86 上 建筑学。几乎没有 你得到的二进制文件特别好 为其中任何一个进行了调整。你下载 Mozilla 的最新版本,它会 几乎可以在任何英特尔上运行 架构 CPU。有很多 一个 Linux 二进制文件。很一般, 它是用 GCC 编译的,即 不是一个很好的 C 编译器。

    当 HotSpot 运行时,它确切地知道 你正在运行什么芯片组。它 确切地知道缓存是如何工作的。它 确切地知道内存层次结构 作品。它确切地知道所有的 流水线互锁在 CPU 中工作。 它知道什么指令集 该芯片具有的扩展。它 精确优化什么机器 轮到你了。然后是另一半 是它实际上看到了 应用程序在运行时。它能够 有统计数据知道哪些 事情很重要。它能够 C 编译器可以内联的东西 永远不会做。得到的东西 Java 世界中的内联很漂亮 惊人的。然后你把它附加到 存储管理的工作方式 现代垃圾收集器。带一个 现代垃圾收集器,存储 分配速度极快。

    【讨论】:

    • “我们几乎总是击败真正优秀的 C 和 C++ 编译器”...“GCC 不是一个非常好的 C 编译器”...“使用现代垃圾收集器,分配非常快”...这只是营销和拖钓。
    • 正如上面的人所说 - 这只是营销和拖钓。说得好。不正确的原因
    • Java dosent 甚至提供了一种使用堆栈的方法——如何认真对待它的性能
    • 即使现在 Java 的执行速度比 C++ 慢大约 1.5 到 2 倍,比 C 慢 3 倍。随着编译器/解释器的成熟,它们变得更加高效,所以说字节码解释器是可笑的比编译器快。 “了解运行时信息可以进一步指导优化”这是一个公平的观点,但与之相对的是,将 VM 分发到数百个平台需要代码在“通用 x86 架构”上运行。不存在对所有这些进行微调的人力。
    • Wikipedia 也为我的论点提供了支持,指出尽管 Jake2 在某些平台上的执行速度比 C 快,但它是可以做到的少数程序之一,而且基准测试不够透明,无法得出结论它的真实性。
    【解决方案4】:

    Java 字节码比大多数原生操作码更容易优化。因为字节码是有限制的,不能做一些危险的事情,所以可以优化得更充分。以指针别名为例。 http://en.wikipedia.org/wiki/Pointer_aliasing

    在 c/c++ 中你可以这样做

    char[] somebuffer = getABuffer();
    char* ptr = &someBuffer[2];
    memcpy(ptr, somebuffer, length);
    

    这使得在某些情况下难以优化,因为您无法确定什么是指什么。在 Java 中,这种事情是不允许的。

    一般而言,您可以在更高抽象级别上执行的代码突变比在目标代码上执行的更强大。

    【讨论】:

      【解决方案5】:

      快速 JVM 使用即时 (JIT) 编译。字节码在运行时即时翻译为本机代码。 JIT 提供了许多优化机会。有关 JIT 的更多信息,请参阅this Wikipedia article

      【讨论】:

      • 很棒的文章,特别注意最后 历史 部分中的 HPA-8000。不久前我读过这篇论文——HPA-8000 基本上模拟了自身,并且这样做更快。
      猜你喜欢
      • 2019-01-31
      • 2012-07-13
      • 1970-01-01
      • 1970-01-01
      • 2017-01-18
      • 2013-08-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多