Java 运行时性能与本机 C/C++代码?

2022-09-01 00:06:27

与C++或C相比,我越来越习惯于用Java编程。我希望了解使用JVM解释器所产生的性能损失,而不是在本地执行相同的“项目”。我意识到这里有一定程度的主观性。该计划的质量将在很大程度上取决于良好的实施。我对一般意义上的以下方面感兴趣:

  • 使用解释器时,必须有一些开销基线。有没有一些一般的经验法则需要记住?10% 15%?(我凭空拉出这些数字)我偶尔会读到博客,说Java代码几乎和原生代码一样快,但我认为这可能是有偏见的。

  • JVM 垃圾回收器是否会显著增加运行时性能的开销?我知道Cocoa应用程序已经开始使用垃圾回收模型,我同意它使编程变得简单得多,但是代价是什么?

  • 从 Java 进行系统调用的开销是多少?例如,创建一个 Socket 对象,而不是 C socket API。

  • 最后,我记得在某处读到JVM实现是单线程的。如果这是真的(我对此持怀疑态度),这是否意味着Java线程真的不是真正的线程?一般来说,Java线程是否对应于内核提供的底层线程?Java应用程序是否像本机应用程序从多核/多个CPU中受益一样?

任何了解JVM和Java程序性能复杂性的开发人员的建议将不胜感激。谢谢。


答案 1

Java不是一种解释型语言,也没有几个版本。Java 字节码是动态 JIT 的。(从技术上讲,它仍然解释一些代码,但是任何在性能方面重要的东西都会被JIT'ed)

至于性能,到底是什么让你疯狂地认为“有一个开销基线”?没有。从来没有,也永远不会有。不是C++和Java之间的,也不是在Python和Javascript或任何其他两种语言之间。有些事情,你的特定版本的JVM会比你的特定C++编译器做得更快,而你的特定C++编译器会比你的特定JVM做得更好。

因此,你选择的语言的“开销”完全取决于1)你希望你的代码做什么,2)你如何编写你的代码。

如果你把一个Java程序翻译成C++,结果几乎肯定会运行得更慢。

如果你把一个C++程序翻译成Java,那也会运行得更慢。

不是因为一种语言比另一种语言“更快”,而是因为原始程序是为一种语言编写的,并且经过定制,可以在语言中很好地工作。任何将其翻译成另一种语言的尝试都将失去这一优势。你最终会得到一个C++风格的Java程序,它不会在JVM上有效运行,或者一个Java风格的C++程序,它也会运行得很糟糕

这两种语言规范都不包含“并且结果必须至少比语言y慢x%”的子句。您的C++编译器和JVM都尽最大努力使事情进展得很快。

然后,您今天看到的性能特征可能会在明天发生变化。语言没有速度。

但要回答您的具体问题:

使用解释器时,必须有一些开销基线。有没有一些一般的经验法则需要记住?10% 15%?我偶尔会读到一篇博客,说Java代码几乎和原生代码一样快,但我可能有偏见。

如上所述,视情况而定。对于许多常见任务,您通常不会看到超过百分之几的差异。对于某些用例,您将看到更大的差异(无论哪种方式。这两种语言在性能方面都有优势。JVM有一些开销,但也有大量的优化机会,尤其是垃圾回收器)

JVM 垃圾回收器是否会显著增加运行时性能的开销?我知道Cocoa应用程序已经开始使用垃圾回收模型,我同意它使编程变得简单得多,但是代价是什么?

基本上没有。平均而言,垃圾回收器比手动内存管理得多,原因有很多:

  • 在托管堆上,动态分配可以更快地完成
  • 共享所有权可以以微不足道的摊销成本进行处理,在母语中,您必须使用非常昂贵的参考计数
  • 在某些情况下,对象销毁也大大简化(大多数Java对象可以通过GC'ing内存块来回收。在C++析构函数必须始终执行,几乎每个对象都有一个)

GC的主要问题是,虽然平均而言垃圾回收器的性能更好,但您无法控制何时承担性能成本。手动内存管理可确保线程在等待清理内存时不会停止。垃圾回收器几乎可以随时决定暂停该过程并清理内存。在几乎所有情况下,这都足够快,没有问题,但对于重要的实时内容,这是一个问题。

(另一个问题是你失去了一点表现力。在C++中,RAII用于管理各种资源。在Java中,你不能使用RAII。相反,GC为您处理内存,对于所有其他资源,您被搞砸了,并且必须自己做很多尝试/最终块。RAII没有理由不能用GC的语言实现,但它在Java或C#中都不可用)

从 Java 进行系统调用的开销是多少?例如,创建一个 Socket 对象,而不是 C socket API。

大致相同。为什么会有所不同?当然,Java必须调用相关的操作系统服务和API,所以有一点点开销,但实际上你可能不会注意到。

最后,我记得在某处读到JVM实现是单线程的。如果这是真的(我对此持怀疑态度),这是否意味着Java线程真的不是真正的线程?一般来说,Java线程是否对应于内核提供的底层线程?Java应用程序是否像本机应用程序从多核/多个CPU中受益一样?

Java可以使用多个线程,是的。JVM本身可能是单线程的(从某种意义上说,所有的JVM服务都在同一线程上运行),我不知道这一点。但是,您的 Java 应用程序可以使用任意数量的线程,并且它们映射到操作系统线程,并将使用多个内核。


答案 2

Java和c#(以及objective-c)的速度都不如原生代码那么快。但是,这只有在您遇到不受工程时间限制的问题时才重要。因为您将有时间使用高级语言设计更好的算法。

所以基本上,如果你正在开发一个设备,你打算每年构建一百万个,或者电池供电,你不会使用java或c#来构建它的核心功能。不过,您可以添加一个lisp解释器来简化自定义。微软不会使用c#作为SQL服务器的核心,其中性能确实很重要。另一方面,Visual Studio可以期望用户拥有高端硬件,可以用作缓慢但高生产率技术的展示。

请注意,我目前的大部分编程都是用Pharo Smalltalk完成的,它比java,c#或objective-c慢得多,甚至不是最快的Smalltalks之一。生产力胜过绩效。


推荐