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)和垃圾回收?为什么如果它更快,仍有延迟?
这里似乎是一个矛盾,有人可以解雇吗?
答案 0 :(得分:10)
在书中策划编程,James Gosling解释说:
詹姆斯:没错。这些天我们都是 打败真正优秀的C和C ++ 编译器几乎总是。当你 转到动态编译器,你得到 编译器的两个优点 在最后一刻跑。一 你知道什么是芯片组吗? 你正在奔跑。这么多次 人们正在编译一块C 代码,他们必须编译它才能运行 关于通用x86的种类 建筑。几乎没有 你得到的二进制文件特别好 调整了他们中的任何一个。你下载了 Mozilla的最新版本,它会 几乎任何英特尔都可以运行 架构CPU。有很多 一个Linux二进制文件这很通用, 它是用GCC编译的 不是一个非常好的C编译器。
当HotSpot运行时,它确切地知道 你在运行什么芯片组。它 确切地知道缓存是如何工作的。它 确切知道内存层次结构 作品。它确切地知道所有的 管道互锁在CPU中工作。 它知道什么指令集 这个芯片有扩展。它 精确地优化什么机器 轮到你了。然后是另一半 是它实际上看到了 应用程序正在运行。它能够 有统计数据知道哪些 事情很重要。它能够 C编译器可以内联的东西 永远不会做。得到的东西 在Java世界中内联很漂亮 惊人。然后你抓住那个 存储管理的工作方式 现代垃圾收集者。有了 现代垃圾收集器,存储 分配非常快。
答案 1 :(得分:9)
快速JVM使用即时(JIT)编译。字节码在运行时即时转换为本机代码。 JIT提供了许多优化机会。有关JIT的更多信息,请参阅this Wikipedia article。
答案 2 :(得分:4)
最快的是根据收集的性能特征,动态地将字节代码编译为本机代码。所有这些都需要额外的内存,所以他们以内存为代价购买速度。此外,最高速度需要一段时间才能到达,因此短期计划不会带来好处。
即便如此,JamVM解释器(与Oracle JVM相比很小)仍然达到了编译JVM合理分数的最高速度。
关于垃圾收集,速度再次来自拥有足够的内存。此外,真正的好处来自于从代码中删除责任以跟踪对象何时不再使用。这导致更简单,更不容易出错的程序。
答案 3 :(得分:3)
这是一个古老的论点。几乎所有流行的都是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慢。答案 4 :(得分:2)
Java Byte代码比大多数本机操作码更容易优化。由于字节代码受到限制,并且您无法执行某些危险操作,因此可以更加充分地进行优化。例如,使用指针别名。 http://en.wikipedia.org/wiki/Pointer_aliasing
在c / c ++中你可以做到
char[] somebuffer = getABuffer();
char* ptr = &someBuffer[2];
memcpy(ptr, somebuffer, length);
这使得在某些情况下难以优化,因为您无法确定所指的是什么。在Java中,这种事情是不允许的。
通常,您可以在更高的抽象级别上执行的代码突变比在目标代码上执行的更强大。