Java运行时性能与原生C / C ++代码?
我已经变得越来越习惯Java编程,而不是使用C ++或C编程。我希望能够理解使用JVM解释器导致的性能下降,而不是本机执行相同的“项目”。 我意识到这里有一定程度的主观性, 该scheme的质量将取决于很好的实施。 我对一般意义上的以下几个方面感兴趣:
-
使用解释器时,必须有一些开销基线。 有一些一般的经验法则要记住吗? 10%15%? (我把这些数字抽出来)我偶尔看过博客,说Java代码几乎和原生代码一样快,但我认为这可能是有偏见的。
-
JVM垃圾收集器是否增加了运行时性能的显着开销? 我知道cocoa应用程序已经开始使用垃圾收集模型,我同意它使编程更简单,但是花费多less?
-
从Java进行系统调用的开销是多less? 例如,创build一个Socket对象而不是C socket API。
-
最后,我记得在某处阅读JVM实现是单线程的。 如果这是真的(我怀疑),这是否意味着Java线程真的不是真正的线程? 通常,java线程是否对应于底层的内核提供的线程? Java应用程序是否能像本地应用程序从多核/多CPU一样获益呢?
任何了解JVM和Java程序性能错综复杂的开发人员的build议都将不胜感激。 谢谢。
Java不是一种解释型语言,而且还不是多个版本。 Java字节码在运行中被JIT处理。 (从技术上来说,它仍然会解释一些代码,但任何重要的性能问题都会被JIT处理)
至于performance,地球上有什么疯狂的想法,“有开销的基线”? 没有。 从来没有,永远不会。 不在C ++和Java之间,而不在Python和Javascript之间,或任何其他两种语言之间。 有些东西是你的特定版本的JVM比你特定的C ++编译器做得更快,而你特定的C ++编译器会比你的特定的JVM做得更好。
所以你select的语言的“开销”完全取决于1)你想要你的代码做什么,2)你如何编写你的代码。
如果你拿一个Java程序并把它翻译成C ++,结果肯定会变慢。
如果你把一个C ++程序翻译成Java,那么也会运行得更慢。
不是因为一种语言比另一种语言“更快”,而是因为原来的程序是为一种语言编写的,而且是专门用这种语言编写的。 而任何将其翻译成另一种语言的尝试都将失去这种优势。 你最终将得到一个C ++风格的Java程序,它不能在JVM上有效运行,或者是一个Java风格的C ++程序,它也会运行得非常好。
语言规范都不包含“和结果必须比语言y慢至lessx%”的子句。 C ++编译器和JVM都尽其所能,让事情变得更快。
然后你今天看到的performance特征可能会在明天改变。 语言没有速度。
但要回答你的具体问题:
使用解释器时,必须有一些开销基线。 有一些一般的经验法则要记住吗? 10%15%? 我已经阅读了偶尔的博客,说Java代码几乎和原生代码一样快,但我可能有偏见。
如上所述,这取决于。 对于许多常见的任务,通常不会看到超过百分之几的差异。 对于一些用例,你会看到更大的差异(不pipe怎样,两种语言在性能方面都有优势,JVM有一些开销,但是也有很多优化的机会,尤其是垃圾收集器)
JVM垃圾收集器是否增加了运行时性能的显着开销? 我知道Cocoa应用程序已经开始使用垃圾收集模型,我同意它使编程更简单,但费用是多less?
基本上没有。 平均来说,垃圾收集器比手动内存pipe理要快得多 ,原因很多:
- 在托pipe堆上,dynamic分配可以更快地完成
- 共享所有权可以被忽略不计的摊销成本处理,在母语中,您必须使用非常昂贵的引用计数
- 在某些情况下,对象销毁也大大简化(大多数Java对象只能通过GC对内存块进行回收,而在C ++中,析构函数必须始终执行,几乎每个对象都有一个)
GC的主要问题在于,虽然垃圾收集器的平均执行效率较高,但您在何时取得性能成本方面失去了一些控制权。 手动内存pipe理可确保您的线程在等待内存清理时不会暂停。 垃圾收集器几乎可以在任何时候决定暂停进程并清理内存。 在几乎所有的情况下,这个速度足够快,没有问题,但对于重要的实时性问题,这是一个问题。
(另外一个问题是你失去了一点performance力,在C ++中,RAII用于pipe理各种资源,在Java中,你不能使用RAII,而是为你处理内存,对于所有其他资源,你被搞砸了,必须用try / finally块做很多事情,没有理由为什么RAII不能用GC语言实现,但是在Java和C#中都没有。
从Java进行系统调用的开销是多less? 例如,创build一个Socket对象而不是C socket API。
大致相同。 为什么会有所不同? 当然,Java必须调用相关的操作系统服务和API,所以会有一点点的开销,但实际上你没有注意到。
最后,我记得在某处阅读JVM实现是单线程的。 如果这是真的(我怀疑),这是否意味着Java线程真的不是真正的线程? 通常,java线程是否对应于底层的内核提供的线程? Java应用程序是否能像本地应用程序从多核/多CPU一样获益呢?
Java可以使用多个线程,是的。 JVM 本身可能是单线程的(就所有的JVM服务在同一个线程上运行而言),我不知道这一点。 但是您的Java 应用程序可以使用尽可能多的线程,并将其映射到操作系统线程并使用多个内核。
请参阅这里 ,了解详细的比较。
java和c#(和objective-c)都不如本地代码那么快。 但是,如果您遇到工程时间有限的问题,这一点很重要。 因为你有时间用高级语言来devise一个更好的algorithm。
所以基本上,如果你正在开发一个你要打造一年一百万的设备,或者那是一个电池供电的设备,你不要使用java或c#来构build它的核心function。 不过,您可以添加一个lisp解释器来使自定义变得简单。 微软不会将c#用作SQL服务器的核心,而性能真的很重要。 另一方面,MS可以期望用户拥有高端硬件的Visual Studio可以用作缓慢而高效的技术的展示。
请注意,我目前在Pharo Smalltalk中执行大部分编程,这比java,c#或objective-c慢很多,甚至不是最快的Smalltalk之一。 生产力胜过性能。
很多人低估了java的性能。 我曾经好奇过,并用java编写了一个简单的程序,然后在c中写了一个等价物(不过是用for循环和一个巨大的数组做一些操作)。 我不记得确切的数字,但我知道,当c程序没有编译任何优化标志(在gcc下)时,java击败了c。 正如所料,当我最终采取积极的优化进行编译时,C拉开了序幕。 说实话,这不是一个以任何方式进行的科学实验,但它确实给了我一个知道java在哪里的基础知识。
当然,当你开始做需要系统调用的事情时,java可能会落后得多。 虽然,我已经看到100MB / s的磁盘读取性能和networking与Java程序运行在适度的硬件上。 不知道那是什么意思,但它确实表明,这对我所需要的任何东西来说都足够好了。
至于线程,如果你的Java程序创build2个线程,那么你有2个真正的线程。
http://www.w3sys.com/pages.meta/benchmarks.html
http://www.freewebs.com/godaves/javabench_revisited/
http://en.wikipedia.org/wiki/Comparison_of_Java_and_C%2B%2B#Performance
http://blog.dhananjaynene.com/2008/07/performance-comparison-c-java-python-ruby-jython-jruby-groovy/
http://www.irrlicht3d.org/pivot/entry.php?id=446
等等。 事实是 – 没关系 。 瓶颈和缓慢的软件是由开发人员,而不是语言(至less现在)。
要解决您的每一点:
- 解释代码的开销远远高于10-15%(我猜的是3x-5x或更高)。 为了降低到10-15%,你必须使用某种forms的机器代码编译步骤(即JIT)。 (尝试在JITclosures的情况下运行JVM,你会看到性能下降像一块石头。)
- 垃圾收集确实会对性能产生影响,但是我想说大家都认为这是值得的。 如果你能承受字节码的编译/解释开销,你也可以承担gc开销。
- Java中的Socket编程比C / C ++更容易,如果这就是你所要求的。 性能方面,套接字I / O开销在Java执行开销上占主导地位。
- 大多数现代JVM都有真正的线程,即每个Java线程都由内核线程执行,从而允许Java线程使用现代多核CPU。
重要的是要记下
Java字节码JIT编译成特定于特定硬件的更优化的代码
VS
C代码编译和优化到通用硬件,所以它不能利用特定硬件提供的function
实际上,虚拟机可以在运行时进行很多优化,基于仅在运行时可用的信息,C / C ++编译器无法做到。 所以,在大多数情况下,JVM至less和原生程序一样快。
Brian Goetz回答了大部分(如果不是所有的话)都是在谈论一个普遍的虚拟机 。
由于你的目标是非常温和的“我希望能够感受到性能的影响……”你应该能够通过检查计算机语言基准游戏中显示的程序和测量来实现其中的大部分。
正如你所知道的Java和C ++
-
您可以查看程序源代码,并自行决定哪些Java程序可以与C和C ++程序进行比较
-
你可以看十几个不同的任务,并自己决定其中哪一个练习“每种语言最基本的特征”
-
您可以查看多核的不同方法 ,或者将程序强制转换为一个核心
-
您可以检查有多lessJVM启动可能会或可能不会影响这些测量结果
但是你必须考虑一下,微小程序的测量是否可以合理地表明应用程序的可能性能 。
这不是一个简单的答案。 编写C风格的C ++是可能的(甚至是一个好主意),但是一旦你尝试在C中进行inheritance,事情变得很难看。 因此,忽略C,并使用Java-vs-C ++,因为它们彼此更接近。
为了真正理解它,你需要用两种语言以相似的方式编写两个相对较大的应用程序。 如果你这样做,那么你使用STL和Java集合类,或者你写你自己的,并在语言之间移植它们? 如果你使用本地的,那么它取决于哪个实现更快,就像你使用你自己的那样,你不是在testing应用程序的真实速度。
我会说,你需要编写应用程序尽可能相似,但使用语言特定的库/成语,它是有道理的。 C ++和Java代码虽然相似,却有不同的处理方式 – 在Java中很简单的东西在C ++中可能非常困难,反之亦然。
一个现代的GC实现不会增加太多的开销,如果你喜欢,你可以切换到C ++的GC进行比较:-)
Java运行时可以做的一些事情通常不是在C ++编译器中完成的,例如内联虚拟方法的能力。
对于系统types的东西,Java通常要求调用C语言,所以在那里有开销(尽pipeJNI比以前要快)。
线程依赖于实现。 Sun曾经使用过“绿色线程”,但对于Solaris来说,这已经很久了,就我所知,大多数(所有)现代虚拟机都使用本地线程。
总之,我不认为Java-vs-C ++的开销%有一个很好的指标,你发现任何可能是微代码都不代performance实世界(不幸的是)。