能否比同样经过优化的C程序更快地运行Java程序?

5
关于C/C++优化在编译时生成,而Java优化在运行时生成的事实。是否可能使Java程序比已经优化的C程序更快?
我了解到运行时优化可能比编译时优化更好。因此,我想知道这些优化的收益是否可以与运行JVM的开销进行比较。

3
现今的处理器性能已经非常高,因此几乎没有必要进行优化。您应该专注于业务逻辑,如果真的需要优化代码,那么可以在以后再进行。 - Anirudha
很容易。将一个良好实现的Java数据结构与一个天真的(但经过优化编译)C等效物进行比较。 - ugoren
我只是想提一下,我并没有要求代码,也不是一个特定的编码问题。我知道我可以用Java编写一个比C++(未优化)运行得更快的程序,例如链接。但我无法想象如何使Java程序比其在C++中的版本(已优化)更快。@Rekin和@Cyan对我的问题提出了见解,但我想让它保持开放状态一段时间,或者有人展示JVM运行时优化,这些优化在编译C++代码时不适用,即gcc -O3 - Antonio
4个回答

10
理论上,是的。但在实践中,这种可能性极小。
其中一个基本假设是,C / C ++只编译一次以获取二进制操作码目标,而Java则编译为正在运行的特定机器。这应该给Java带来优势。但现实情况是,即使是C / C ++也可以有几条优化路径,在运行时动态选择,并获得针对特定目标的编译的大部分好处。
相反,正如Rekin所述,Java JVM需要动态地对Java程序进行分析,以了解要优化的内容以及如何优化。分析本身就是一个昂贵的操作,并且Java JVM无法摆脱这种开销。另一方面,选择适当的优化集可以提供优势。实际上,大多数C程序(但不是全部 :))都为其任务进行了良好的调整,使用分析技术几乎没有留下什么可优化的余地。
在Java中还有其他效果,它们完全超过了这些编译问题。可能排在第一位的是垃圾回收器。
垃圾收集器的第一个任务是简化编程,照顾和避免C / C ++中最讨厌的经常性错误之一,即内存泄漏。单靠这个功能就足以证明Java在许多工业环境中的广泛使用。
然而,它有一个很大的代价。非常大的代价。根据研究,必须可用约5倍于严格必要内存量的内存,以确保垃圾收集器以最小的开销工作。因此,每当这种数量的内存不足时,GC开销开始变得显着,将性能降至爬行。
相反,在某些情况下,从内存分配负担中释放算法可能允许更改算法并采用更好,更快的算法。在这种情况下,Java可以获得优势,并比C程序更快。
但是正如您所料,这是不常见的...

2
我曾经读过,JVM可以进行一些非常激进的优化。最终结果是高性能机器码。所以,一旦它到达那里,它就可以竞争了。问题是:要知道何时编译热点需要确定。这意味着不断的分析。这是一个重要的开销,但更糟糕的是:确定优化是否可行的算法具有Big-Oh O(N^2)或甚至O(N^3)的复杂度。我是从JVM工程师的博客上读到的。看看我能否找到来源... - Rekin
1
请记住,仅仅“找到”热点已经是相当不容易的工作了。 - MSalters
1
根据研究,为确保垃圾收集器最小化开销,需要提供大约5倍于必需内存的可用内存。只有一项[1] 研究做了这样的探究,它并没有使用如Oracle所提供的先进JVM和先进GC,而是采用了模拟方式。该论文与经验相矛盾 - 许多应用程序在只有活动内存的1.5倍左右的情况下运行,并且没有明显的GC开销。考虑到C++手动分配器也存在一定的碎片问题,这并不是我称之为“巨大成本”的东西。 - Piotr Kołaczkowski
[1] https://people.cs.umass.edu/~emery/pubs/gcvsmalloc.pdf - Piotr Kołaczkowski
只有当n很大时,O(N^3)复杂度才显得重要。许多优化算法适用于非常小的“N”,因为N通常是每个方法调用中的变量数或分支数。 - Piotr Kołaczkowski
这是一个非常好的观点,Piotr。应该更好地评估GC成本。 不幸的是,在商业利益存在的情况下,很少有更多理由相信制造商的声称,而不是具有有限工具的.edu研究。我担心这个问题可能会变得政治化,并且我认为可以相对简单地创造一种相对友好或相对令人讨厌的GC性能场景。因此,由于信息来源受到限制的原因,也许我们只能使用谨慎的措辞“GC需要比正常工作所需的内存更多”。 - Cyan

2
由于C/C++程序是专门为特定平台编写并直接编译成机器码,因此它们与其运行的软件/硬件平台更加接近,因此速度更快。
Java优化内置于JVM中,最佳优化(以执行程序的速度为标准)是通过即时(JIT)处理字节码实现的。虽然JIT被证明更加占用内存。
因此,比较这些策略清楚地显示出C/C++本机代码将更快;因为即使使用JIT,JVM仍然需要一些开销将字节码转换为本机代码。
但这是依赖平台和Java更具可移植性所付出的代价。
引自when is java faster than c++ (or when is JIT faster then precompiled)?,我发现在以下情况下Java执行可能会优于C/C++:
大量小内存分配/释放。主要JVM具有极其高效的内存子系统,并且垃圾回收可以比要求显式释放更有效(还可以移动内存地址等等)。
通过深层次方法调用的高效访问。 JVM非常擅长省略不必要的内容,通常比大多数C ++编译器(包括gcc和icc)更好,部分原因是因为它可以在运行时进行动态分析(即可以过度优化并仅在检测到问题时取消优化)。
将功能封装到短暂的小对象中。

2
JVM 倾向于更好地优化掉那些没有任何用处的代码。具有动态编译的能力意味着它可以基于运行时才知道的信息进行优化。 - Peter Lawrey

1
JVM的开销很大。它必须加载几个类,这些类位于zip(jar)文件中并需要被提取出来。
对于每个被加载的类,都会运行一些静态分析方法,以查看是否存在无法访问的代码、操作数栈类型问题和其他问题。
然后,一个分析器始终在运行,以决定哪些代码部分值得优化,通常意味着这些方法需要被调用几千次才能被优化。
除此之外,你还要面对垃圾收集器。
我真的想象不出一个为其所运行的平台编译的正确编写的C程序会被Java等效程序超越。也许只有当你遇到一些罕见的边缘情况,其中JVM具有某些优化而C编译器没有实现该特定优化时,才可能发生。

1
你的第一段主要是针对那些试图在Java中编写运行时间只有几分之一秒(例如/bin/ls)的程序的人。一个典型的服务器运行时间长达数天或数年,所以...... - maaartinus

1
在资源有限且时间至关重要时,我发现Java比C运行更快。在这种情况下,您没有足够的时间编写像C和C++中那样高效的代码,您可能会执行比JVM为您执行的不那么高效的操作。例如,如果您已经需要JVM所做的事情,它可能会更快。
如果您拥有足够资源的计算机,则开发人员的时间更加昂贵/关键,并且您可以在更短的时间内获得工作稳定的系统,并有时间进行分析/优化,而C团队可能仍在修复所有核心转储。您的结果可能会有所不同。
对于资源受限设备,C仍然占主导地位,因为您可以控制资源分配。顺便说一句,现在大多数手机都可以很好地运行Java(或Objective-C)。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接