任何人都可以量化C ++和Java之间的性能差异吗?

时间:2008-11-24 04:55:02

标签: java c++ performance comparison

Java在JIT之前最初很慢,但今天的性能非常接近C ++。我想知道是否有人在两种语言之间进行了可衡量的性能比较? 与C ++相比,Java在哪些方面不足? Java为开发人员提供了许多生产力提升,因此他们可以更快地编写应用程序,因为垃圾大学,缺乏指针等等。应用程序如Firefox,Webkit和Open例如,如果使用100%Java编写Office,可能会更快,更可靠地开发Office,可能是2倍,但开发人员仍然出于性能原因选择C / C ++。有人可以证明Java不能像我提到的那样为应用程序执行C ++。

我想补充说,由于某种原因,仍然在C ++中完成了很多应用程序工作。这不仅仅是一个主观问题。具有较高抽象级别的语言经常会造成性能损失。如果没有这种惩罚,我们都会用更高级别的语言进行编程。与C ++相比,Java仍然在哪里支付?具体。

13 个答案:

答案 0 :(得分:34)

语言没有速度。 Java或C ++语言规范都没有指定“并且程序必须编译为这个高效”。

每种语言都指定程序必须执行的事项列表,或者至少似乎执行,这在某些情况下会对程序的效率设置上限,但通常是聪明的编译器可以忽略单个程序中的这些规则,因为所有重要的是程序的行为就像遵循了规范一样。可以内联函数,可以将堆数据移动到堆栈等等。

程序的性能取决于三件事:编译器,底层平台/硬件和程序代码本身。

不是“语言”。你得到的最接近的是编译器。

有充分的理由说明为什么这两种语言比另一种语言更快。 C ++减少了可能会减慢程序执行速度的承诺,但是Java是JIT,这意味着它可能会利用运行时信息来优化代码,而C ++不能轻易做到......然后,无处可去该规范是否说C ++必须被jit'ed。就像我相信也有Java编译器生成本机代码而不是JVM字节码。

只有当您运行的是特定计算机,每种语言的特定编译器以及每种语言的程序的特定实现时,您的问题才有意义在这种情况下,您可以同时运行两者看哪个是最快的

垃圾收集是另一个很好的例子。当然,垃圾收集意味着一些开销,但它也可以实现一些重要的快捷方式。在Java或.NET等托管语言中,堆分配非常便宜,因为管理和垃圾收集。在C ++中,它是......未指定的,当然,但在实践中,通常非常慢,因为操作系统必须遍历堆以在或多或少碎片化的内存空间中找到一个空闲的内存块。哪个最快?取决于操作系统。取决于编译器。取决于源代码。

源代码也有很大的不同。如果您使用Java程序并将其简单地移植到C ++,它将像垃圾一样执行。 C ++不能很好地处理虚拟函数,并且通常有可用的高级替代品。在C ++中,堆分配可能非常慢,所以再次,天真地重新实现Java程序将是非常低效的。当采取相反的方式时也是如此。如果直接移植到Java,许多C ++习语会不必要地变慢。因此,即使您已经确定了一个平台和一个编译器,您如何比较程序的性能?要将它转换为编译器,你必须编写它的两个实现,然后它不再是同一个程序。

但是,我认为可以公平地说,在大多数现代硬件上,使用现代Java编译器和现代C ++编译器,大多数程序都可以实现非常高效,当然也足够快。但只有你理解了你正在使用的语言,并遵守其规则。如果你试图用C ++编写Java代码,那么Java将会神奇地变得更有效率,反之亦然。

我想对你的问题最简洁的答案是“不。没有人可以量化C ++和Java之间的性能差异”;)

答案 1 :(得分:16)

JIT编译器可以更快地用于许多单独的代码构造,因为它们可以利用代码的运行时分析。

例如,VonC在回答这个问题时提到了所有对象的堆分配。实际上并非如此:如果escape analysis可以证明对象的引用不会超过堆栈帧,则JIT可以在堆栈上分配对象。通过这种方式,编译器可以获得堆栈分配的性能优势,同时程序员可以放心假定GC堆分配的安全性。

类似地,Uri提到了虚函数(在大多数非C ++语言中称为虚方法)。这是另一种情况,JIT编译器具有几乎永远不可用于提前(AOT)编译器的优点:JIT可以插入内联廉价类型检查(解除引用的单词比较)并实际内联虚拟方法调用,如果特定的呼叫站点恰好是单态的(即实际类型在实践中总是相同的)。事实证明,在实践中最多95% of all virtual method calls是单态的,所以这可能是一个相当大的胜利 - 这是AOT编译器难以利用的胜利,因为运行时代码加载可能会动态地改变运行时特性。

答案 2 :(得分:12)

要完成Pax和Uri的回答,这里有一些最近的基准:

如上所述,这是两种非常不同的语言,有些人确信Java will ever be slower than C++因为:{/ p>

  • 所有对象(甚至是像迭代器这样的小对象)的堆分配
  • 许多动态铸件
  • 增加内存使用量

[幽默]

  

“Java是高性能。通过高性能我们意味着足够。足够我们意味着缓慢。” Mr. Bunny

如评论中dribeas所述,堆分配不是一个好的论据 这个“Urban performance legends, revisited”提到:

  

“垃圾收集永远不会像直接内存管理那样高效。”而且,在某种程度上,这些陈述是正确的 - 动态内存管理不是那么快 - 它通常要快得多
  malloc / free方法一次处理一个内存块,而垃圾收集方法倾向于大批量处理内存管理,从而产生更多的优化机会(以可预测性的某些损失为代价)。

答案 3 :(得分:9)

另一个替补席:the shootout

答案 4 :(得分:7)

在很多方面,这就像比较苹果和橘子一样。

C ++建立在你不为任何不使用的东西付费的概念之上。 如果您自己管理内存,如果您不使用虚拟功能等

Java并没有给你那种自由。它为您提供了您可能不想要的功能。对于你可能想要自己分配内存的所有内容,你必须为所有内容使用堆对象,这样你就会受到垃圾收集的影响。

一旦你开始谈论GUI,这是一个更加困难的比较,因为不同的UI框架和工具包有不同的性能问题。例如,Swing / AWT通常比直接为本机OS编写的内容慢。在C ++中,您很少会找到真正的便携式工具包等。

我认为当开发人员启动openoffice时,Java速度要慢得多,而且UI工具包很慢而且很丑陋。像Eclipse这样的工具证明你甚至可以在Java中构建相对优秀的UI,但不可否认,SWT是一个在本机级别执行大量工作的工具包。

答案 5 :(得分:7)

许多人忘记了JIT技术可以应用于任何类型的二进制文件,甚至是由C ++编译器生成的二进制文件。如果您使用类似HP的Dynamo(一种运行可执行文件的模拟器比运行和模拟的本机芯片更快),JIT编译Java的大部分好处对C ++也有效。运行时分析实际上不是Java的性能优势,而是JIT编译的一般性。

答案 6 :(得分:6)

对我来说,这个问题有点像红色鲱鱼(也许不是故意的)。这是一个非常错误的问题。

要问的第一个问题是这些

  1. 什么让我的程序变慢?
  2. 对于我的新计划,关键性能设计考虑因素是什么?
  3. 以下是一些很好的'为什么'的问题

    • 是否有太多不必要的I / O?
    • 是否使用了太多内存?
    • 内存分配器是否被破坏(分配太多,细粒度对象太多)
    • 我的程序是否长时间在网络I / O上被阻止
    • 确实有错误的地方

    我怀疑你真的需要专注于你的程序的 P 性能方面(使用大写'P')来表示 p 性能(小'p' ')方面首先。如果你能够达到语言障碍的程度,那么你在表现方面做得非常好。

    对于新代码 - 预先计划性能和效率非常重要。我总是建议性能和效率与任何其他功能(它们都是功能)一样对待:就像UI bling或可靠性一样。 当然这取决于很多事情 - 但是当它很重要时,你需要事先做好计划:

    • 选择适合数据集和预期缩放的数据结构和算法
    • 适当的基于多线程UI的应用程序(UI线程,后台/处理线程)
    • 计划了解长网络I / O延迟
    • 计划设定目标并预先衡量绩效 - 定期运行回归测试
    • 测量内存使用量 - 记忆猪的速度很慢(让japes开始:))
    • 当有事件,回调或其他通知机制时,不要轮询

    我认为这是一个红色鲱鱼的原因是很少有人可以在C ++和Java之间做出选择 - 它们是非常非常不同的语言,具有非常不同的运行时间。我怀疑更常见的是你有其他限制因素推动你 - 这些将是比语言表现更高阶的因素。可与现有代码,现有员工的技能和经验等进行计算。

    环境也有所不同。例如,Java几乎永远不会是寡妇客户端(与Web)应用程序的正确选择。相反,原生C ++几乎永远不会成为基于Web的应用程序的选择。 (注意,我是一个Windows家伙 - * nix中的情况可能非常不同。)

答案 7 :(得分:5)

我不相信任何人都可以证明C ++总是比Java快得多,因为你总是可以恢复到JNI以从Java获得原生速度。

例如,参见SWT,它是由IBM构建的图形工具(我认为)意味着取代Swing并提供本机性能和外观。

对于其中一个人来说,我更喜欢开发速度超过速度,因为我认为最小开发时间比原始应用程序速度更重要,特别是当我仍然可以达到这个速度时 - 我可以同时具备易于开发的特性Java 编译语言的速度。

答案 8 :(得分:5)

要考虑的一些要点:

  • 如果你有一个更好的C ++编译器,你的代码不会变得更快。您需要先重新编译它。如果您获得了更好的JVM,那么所有Java代码都将运行得更快

  • 如果你有一个更好的C ++编译器/ JVM,你会看到执行速度提高10-20%,通常是在极端情况下。如果您找到更好的算法来实现您的需求,您可以轻松获得1,000%-10,000%的性能,有时甚至更多。

所以今天,如果表现是一个问题,你应该看看这两个事实:

  • 语言用一种算法替换另一种算法有多容易? (a.k.a“重构”)
  • 你能用多快的速度编写代码?

其他任何东西都只是FUD。

答案 9 :(得分:5)

我已经在C和Java中实现了对性能敏感的应用程序(物理模拟,财务模型)。实际情况是,通过改变算法而不是通过调整实现,我总能获得更大的性能提升 - 但实现也很重要。至于现在,我的观点是Java比C慢(我对C ++中的数字没有那么多经验),但通过仔细调整可以获得很多,而且这种调整在Java中要容易得多,因为你不必处理分段错误,双重释放等.C ++占据了中间地带,因为现代C ++技术(智能指针,模板,STL容器)提供了速度和相对的使用安全性。

答案 10 :(得分:3)

  

与C ++相比,Java在哪里不足?

很好的问题。与C ++相比,Java和JVM有两个主要缺陷会削弱性能:

  • 基于类型擦除的泛型。

  • 缺乏价值类型。

前者意味着通用代码会导致装箱和拆箱,这会导致大量不必要的分配以及对缓存不友好的额外间接级别。

后者意味着程序员不可能打开任意数据结构,如复数(浮点数对),哈希表项(键值对)和顶点数据。

这两个问题相结合,使得无法在Java中实现高效的通用哈希表。特别是,.NET解决了这两个问题。例如,Java's generic hash table can be 17× slower than a .NET Dictionary

此外,与C ++相比,JVM的FFI非常慢。我听说只需从Java调用外部C函数就可以进行1000次循环。

答案 11 :(得分:1)

使用Java,C#或任何托管编程语言可以更好地构建一些东西。使用非托管编程语言(如C或C ++)可以更好地构建其他东西

前一类通常包括“应用程序”,而第二类通常包括“平台”。

在Java中构建FireFox或WebKit不仅仅是简单的愚蠢,而且会使最终产品变得非常,非常慢,糟糕并为最终用户浪费大量资源。对于Java,C#或 SmallTalk ,Open Office可能是一个很好的候选者。但是用Java构建FireFox或WebKit(或C#就此而言)显然是愚蠢的,并且是失败保证...

对于很多东西来说,C ++和C的速度要快几个数量级,此外它还会占用一小部分内存。就是那样子。只要Java和C#是“托管”编程语言,这将永远不会改变。也许有一天,CPU会如此之快以至于“无所谓”。但我对此表示怀疑,因为随着更多CPU的出现,人们倾向于屈服于他们的需求......

如果您想构建浏览器,我很遗憾地说您需要自学C或C ++;)

答案 12 :(得分:1)

Java应用程序具有C ++程序所没有的初始化开销。当JITed时,它们不像C ++程序那样进行微优化。此外,运行时开销很小(GC +间接调用开销)。总的来说,这些可量化的差异并不是很多。但是......

众所周知,当Java应用程序首次启动时,它必须激活其磁通电容器才能将其环境带回1995年。这会在启动时引入一点延迟。但是一旦结束,JVM的表现与1995年在硬件上运行的类似C ++程序一样。