C ++性能与Java / C#
我的理解是C / C ++会生成要在特定机器体系结构上运行的本机代码。相反,诸如Java和Crun之类的语言位于虚拟机之上,该虚拟机抽象出了本机体系结构。从逻辑上讲,由于这一中间步骤,Java或者C似乎无法达到C ++的速度,但是有人告诉我最新的编译器("热点")可以达到或者什至超过该速度。
也许这更像是编译器问题,而不是语言问题,但是谁能用通俗的英语解释这些虚拟机语言中的一种比本地语言有更好的表现?
解决方案
仅当Java解释器生成的机器代码实际上比编译器为正在编写的C ++代码生成的机器代码优化的机器代码时才发生,直到C ++代码比Java和解释成本慢的地步。
但是,除非Java有一个写得很好的库,而且我们有自己写得不好的C ++库,否则实际发生的几率很小。
通常,Cand Java可以快或者快,因为JIT编译器(可以在第一次执行IL时对其进行编译的编译器)可以进行优化,而C ++编译的程序无法进行查询,因为它可以查询机器。它可以确定机器是Intel还是AMD;奔腾4,Core Solo或者Core Duo;或者是否支持SSE4等
通常必须事先使用混合优化来编译C ++程序,以使其在所有机器上都能很好地运行,但没有像单个配置(即处理器,指令集,其他硬件)那样优化。
另外,某些语言功能使Cand Java中的编译器可以对代码进行假设,从而可以优化C / C ++编译器无法执行的某些部分。当我们可以访问指针时,有很多优化是不安全的。
Java和Ccan的堆分配也比C ++更为有效,因为垃圾收集器和代码之间的抽象层允许它一次完成所有堆压缩(相当昂贵的操作)。
现在,我不能再说Java了,但是我知道Cfor示例在知道方法主体为空时实际上将删除方法和方法调用。并且它将在整个代码中使用这种逻辑。
因此,我们可以看到,某些Cor Java实现会更快的原因很多。
综上所述,可以在C ++中进行特定的优化,这将使我们无法使用C#进行的所有工作,特别是在图形领域以及我们接近硬件时。指针在这里产生奇迹。
因此,根据我们所写的内容,我会选择其中之一。但是,如果我们编写的内容与硬件无关(驱动程序,视频游戏等),则不必担心C的性能(同样也不能说Java)。会做的很好。
在Java方面,@ Swati指出了一篇不错的文章:
https://www.ibm.com/developerworks/library/j-jtp09275
不解释从Java或者Ccompiler生成的可执行代码-将其编译为"及时"(JIT)的本地代码。因此,在执行过程中首次遇到Java / C程序中的代码时,由于"运行时编译器"(又名JIT编译器)将字节代码(Java)或者IL代码(C#)转换为本机机器指令,因此会产生一些开销。但是,下次在应用程序仍在运行时遇到该代码时,将立即执行本机代码。这就解释了一些Java / C程序最初看起来是缓慢的,但是运行时间越长,性能越好。一个很好的例子是ASP.Net网站。第一次访问该网站时,由于JIT编译器将Ccode编译为本机代码,因此速度可能会慢一些。后续访问导致更快的网站-除了服务器和客户端缓存。
除了其他人所说的以外,据我了解,.NET和Java在内存分配方面更胜一筹。例如。它们可以压缩内存,因为它会变得碎片化,而C ++则不能(本地化,但是如果我们使用的是聪明的垃圾收集器,则可以)。
虚拟机语言不太可能胜过编译语言,但它们可以足够接近而无所谓,至少出于以下原因(由于从未使用过C#,所以我在这里使用Java是因为)。
1 / Java运行时环境通常能够检测经常运行的代码段,并对这些部分执行即时(JIT)编译,以便将来以完整的编译速度运行。
2 / Java库的大部分已编译,因此,当我们调用库函数时,我们正在执行的是编译后的代码,而不是解释代码。我们可以通过下载OpenJDK来查看代码(用C语言编写)。
3 /除非我们要进行大量计算,否则程序在运行的大部分时间中,都是在等待非常慢的(相对而言)人的输入。
4 /由于在加载类时对Java字节码进行了大量验证,因此大大减少了运行时检查的常规开销。
5 /在最坏的情况下,可以将性能密集的代码提取到已编译的模块中,然后从Java中调用(请参阅JNI),以使其全速运行。
总而言之,Java字节码永远不会胜过本机语言,但是有一些方法可以减轻这种情况。 Java的最大优点(如我所见)是巨大的标准库和跨平台的特性。
我不确定即使使用Hotspot,我们会发现Java代码的运行频率比C ++快多少,但是我会花一些时间解释它是如何发生的。
将已编译的Java代码视为JVM的解释性机器语言。当Hotspot处理器注意到某些已编译的代码将被多次使用时,它将对机器代码进行优化。由于手工调优Assembly几乎总是比C ++编译的代码快,因此可以确定以编程方式调优的机器代码不会太糟。
因此,对于高度重复的代码,我可以看到Hotspot JVM可以比C ++更快地运行Java ...直到垃圾回收开始发挥作用。 :)
JIT(及时编译)的速度非常快,因为它针对目标平台进行了优化。
这意味着,无论开发人员在哪个CPU上编写代码,它都可以利用CPU支持的任何编译器技巧。
.NET JIT的基本概念如下所示(大大简化):
首次调用方法:
- 程序代码调用方法Foo()
- CLR查看实现Foo()的类型并获取与其关联的元数据
- 从元数据中,CLR知道IL(中间字节代码)存储在哪个内存地址中。
- CLR分配一块内存,并调用JIT。
- JIT将IL编译为本地代码,将其放入分配的内存中,然后更改Foo()的类型元数据中的函数指针以指向此本地代码。
- 本机代码已运行。
第二次调用方法:
- 程序代码调用方法Foo()
- CLR查看实现Foo()的类型,并在元数据中找到函数指针。
- 在此内存位置的本机代码已运行。
如我们所见,第2次除了具有实时优化的优点外,其处理过程几乎与C ++相同。
就是说,还有其他开销问题会减慢托管语言的速度,但是JIT很有帮助。
在某些情况下,托管代码实际上可以比本机代码更快。例如,"标记清除"垃圾收集算法允许像JRE或者CLR这样的环境在一次通过中释放大量短寿命(通常)的对象,其中大多数C / C ++堆对象一次被释放。一次。
从维基百科:
For many practical purposes, allocation/deallocation-intensive algorithms implemented in garbage collected languages can actually be faster than their equivalents using manual heap allocation. A major reason for this is that the garbage collector allows the runtime system to amortize allocation and deallocation operations in a potentially advantageous fashion.
就是说,我已经编写了许多Cand和C ++,并且运行了许多基准测试。以我的经验,C ++在两种方面比C#快得多:(1)如果我们采用用C#编写的某些代码,请将其移植到C ++,本机代码往往会更快。快多少?嗯,它变化很大,但是速度提高100%并不少见。 (2)在某些情况下,垃圾回收会大大降低托管应用程序的速度。 .NET CLR的大堆(例如,> 2GB)做得很糟糕,并且最终可能花费大量时间在GC上,甚至在具有很少甚至没有中间寿命对象的应用程序中也是如此。
当然,在我遇到的大多数情况下,托管语言足够快,而且远见卓识,而为了获得C ++的额外性能而在维护和编码方面的权衡根本不是一个好方法。
通常,与语言相比,程序的算法对于应用程序的速度将更为重要。我们可以使用任何语言(包括C ++)来实现较差的算法。考虑到这一点,我们通常可以使用一种可以实现更高效算法的语言来更快地编写运行代码。
高级语言通过提供对许多有效的预构建数据结构的更轻松访问以及鼓励可避免低效率代码的实践,在此方面做得很好。当然,有时它们也可以使编写一堆非常慢的代码变得容易,因此我们仍然必须了解平台。
同样,C ++正在赶上STL容器,自动指针等"新"(请注意引号)功能-例如,参见boost库。我们可能偶尔会发现,完成某些任务的最快方法需要使用诸如指针算术之类的技术,该技术在高级语言中是被禁止的-尽管它们通常可以使我们调出使用可以按需实现的语言编写的库。
最主要的是要知道我们使用的语言,与之相关的API,它可以做什么以及它的局限性。
关于我们所问的特定问题,这里有一些很好的答案。我想退后一步,看看更大的图景。
请记住,用户对编写软件速度的看法会受到许多其他因素的影响,而不仅仅是代码生成的优化程度。这里有些例子:
- 手动内存管理很难正确执行(没有泄漏),甚至更难有效地执行(完成后不久释放内存)。通常,使用GC更有可能产生一个可以很好地管理内存的程序。我们是否愿意努力工作,并延迟交付软件,以超越GC?
- 我的C#比我的C ++更易于阅读和理解。我还有更多方法可以使自己确信我的C#代码可以正常工作。这意味着我可以优化算法,减少引入错误的风险(并且用户不喜欢崩溃的软件,即使它崩溃的速度很快!)
- 与使用C ++相比,在C#中创建软件的速度更快。这样可以腾出时间来提高性能,同时仍然可以按时交付我的软件。
- 用C#编写良好的UI比使用C ++更容易,因此我更有可能在UI保持响应的同时将工作推送到后台,或者在程序不得不阻塞一会儿时提供进度或者监听UI。这不会使任何事情变得更快,但是会使用户对等待更加满意。
我所说的关于Cis的一切可能对Java都是正确的,只是我没有经验可以肯定地说。
我喜欢Orion Adrian的回答,但它还有另一方面。
几十年前,关于汇编语言与"人类"语言(如FORTRAN)提出了同样的问题。答案的一部分是相似的。
是的,C ++程序能够比任何给定的(非平凡的)算法都快于Con,但是C中的程序通常会比C ++中的"天真的"实现更快或者更快,并且C ++中的优化版本将需要更长的开发时间,并且仍可能会以很小的优势击败Cversion。那么,真的值得吗?
我们必须一对一地回答该问题。
就是说,我一直是C ++的忠实拥护者,并且我认为它是一种令人难以置信的表达和强大的语言-有时被人们低估了。但是在许多"现实生活"问题中(对我个人而言,这意味着"获得报酬来解决的那种"),Cwill可以更快,更安全地完成工作。
我们付出的最大罚款?许多.NET和Java程序都是内存消耗。我已经看到.NET和Java应用程序占用了"数百"兆字节的内存,而类似复杂性的C ++程序几乎没有占用"数十"兆字节的内存。
JIT与静态编译器
如前几篇文章所述,JIT可以在运行时将IL /字节码编译为本机代码。提到了这样做的代价,但并未得出结论:
JIT的一个大问题是它无法编译所有内容:JIT编译需要时间,因此JIT将只编译部分代码,而静态编译器将生成完整的本机二进制文件:对于某些程序,静态编译器将轻易地胜过JIT。
当然,C(或者Java或者VB)通常比C ++更快地产生可行且健壮的解决方案(如果仅是因为C ++具有复杂的语义,而C ++标准库虽然有趣且功能强大,但与完整版本相比却相当差劲)。 (.NET或者Java标准库的范围),因此通常,大多数用户看不到C ++与.NET或者Java JIT之间的区别,对于那些至关重要的二进制文件,我们仍然可以调用C ++处理从Cor Java(即使这种本地调用本身可能会非常昂贵)...
C ++元编程
请注意,通常,我们正在将C ++运行时代码与其在Cor Java中的等效代码进行比较。但是C ++具有一个可以胜过Java / Cout的功能,即模板元编程:代码处理将在编译时完成(因此,大大增加了编译时间),导致运行时为零(或者几乎为零)。
我到目前为止还没有看到现实的效果(我只玩过概念,但是那时,JIT的执行时间为几秒钟,C ++的执行时间为零),但这是值得一提的,同时模板元编程不是不重要的...
Edit 2011-06-10: In C++, playing with types is done at compile time, meaning producing generic code which calls non-generic code (e.g. a generic parser from string to type T, calling standard library API for types T it recognizes, and making the parser easily extensible by its user) is very easy and very efficient, whereas the equivalent in Java or C# is painful at best to write, and will always be slower and resolved at runtime even when the types are known at compile time, meaning your only hope is for the JIT to inline the whole thing.
...
Edit 2011-09-20: The team behind Blitz++ (Homepage, Wikipedia) went that way, and apparently, their goal is to reach FORTRAN's performance on scientific calculations by moving as much as possible from runtime execution to compilation time, via C++ template metaprogramming. So the "I have yet so see a real life effect on this" part I wrote above apparently does exist in real life.
本机C ++内存使用情况
C ++具有与Java / C#不同的内存使用率,因此具有不同的优点/缺点。
不管JIT优化如何,直接访问内存的操作都不会很快(让我们暂时忽略处理器缓存等)。因此,如果内存中有连续的数据,那么通过C ++指针(即C指针……让Caesar给出应有的条件)对其进行访问将比Java / C#快得多。 C ++具有RAII,即使在Java中,它也比Cor中的很多处理都容易得多。 C ++不需要使用using来限制其对象的存在范围。而且C ++没有finally
子句。这不是错误。
:-)
而且,尽管具有类似Cprimitive的结构,但C ++"在堆栈上"对象在分配和销毁时不会花费任何成本,并且不需要GC就可以在独立线程中进行清理。
至于内存碎片,2008年的内存分配器不是1980年以来通常与GC比较的旧内存分配器:C ++分配不能在内存中移动,是的,但是,就像在Linux文件系统上一样:谁需要硬盘碎片整理何时不会发生?为正确的任务使用正确的分配器应该是C ++开发人员工具包的一部分。现在,编写分配器并不容易,然后,我们大多数人都有更好的工作要做,对于大多数使用而言,RAII或者GC绰绰有余。
Edit 2011-10-04: For examples about efficient allocators: On Windows platforms, since Vista, the Low Fragmentation Heap is enabled by default. For previous versions, the LFH can be activated by calling the WinAPI function HeapSetInformation). On other OSes, alternative allocators are provided (see https://secure.wikimedia.org/wikipedia/en/wiki/Malloc for a list)
现在,随着多核和多线程技术的兴起,内存模型变得有些复杂。在这个领域中,我猜想.NET具有优势,而有人告诉我Java占据了上风。一些"裸机"黑客很容易赞美他的"机器附近"代码。但是现在,与让编译器正常工作相比,手工生成更好的汇编要困难得多。对于C ++,十年来,编译器通常变得比黑客更好。对于Cand Java,这甚至更容易。
尽管如此,新的标准C ++ 0x仍将为C ++编译器提供一个简单的内存模型,该模型将标准化(从而简化)C ++中有效的多处理/并行/线程化代码,并使编译器的优化过程更加轻松,安全。但是接下来,我们将在几年内看到它的诺言是否兑现。
C ++ / CLI与C#/ VB.NET
注意:在本节中,我谈论的是C ++ / CLI,即.NET托管的C ++,而不是本机C ++。
上周,我接受了有关.NET优化的培训,并且发现静态编译器仍然非常重要。比JIT重要。
在C ++ / CLI(或者其祖先,受管C ++)中编译的完全相同的代码可能比在C(或者VB.NET,其编译器产生与C#相同的IL)中生成的相同代码快几倍。
因为C ++静态编译器比C#更好地生成已经优化的代码。
例如,.NET中的函数内联仅限于其字节码长度小于或者等于32个字节的函数。因此,C中的某些代码将产生一个40字节的访问器,而JIT则不会对其进行内联。 C ++ / CLI中的相同代码将产生一个20字节的访问器,该访问器将由JIT内联。
另一个例子是临时变量,这些临时变量只是由C ++编译器编译掉的,而在Ccompiler生成的IL中仍被提及。 C ++静态编译优化将导致更少的代码,从而再次授权进行更具侵略性的JIT优化。
据推测,这样做的原因是事实使得C ++ / CLI编译器受益于C ++本地编译器的大量优化技术。
总结
我爱C ++。
但就我所知,Cor Java总体而言是一个更好的选择。不是因为它们比C ++快,而是因为当我们综合它们的质量时,它们最终会比C ++生产力更高,需要的培训更少并且拥有更完整的标准库。对于大多数程序而言,它们的速度差异(以一种或者另一种方式)可以忽略不计...
编辑(2011-06-06)
我在C#/。NET上的经验
我现在有5个月的几乎完全专业的Ccoding(这使我的CV已经充满了C ++和Java,以及一点C ++ / CLI)。
我玩过WinForms(Ahem ...),WCF(cool!)和WPF(Cool !!!!都通过XAML和原始C#玩过。WPF非常简单,我相信Swing不能与之相比)和C4.0 。
结论是,虽然在C#/ Java中比在C ++中更容易/更快地生成可以在C#/ Java中工作的代码,但要在C中(而不是在Java中)生成更强大,安全和健壮的代码要比在C ++中困难得多。原因很多,但可以归纳为:
- 泛型不如模板强大(尝试编写一种有效的泛型Parse方法(从字符串到T),或者等效的C#中的boost :: lexical_cast来理解问题)
- RAII仍然是无与伦比的(GC仍然会泄漏(是的,我不得不处理该问题),并且只会处理内存。即使C#的" using"也没有那么容易和强大,因为编写正确的Dispose实现很困难)
- C#的readonly和Java的final没有C ++的const有用(没有内置的功能,如果没有大量的工作,就无法在C#中公开只读的复杂数据(例如,节点树)。不可变的数据是一个有趣的解决方案,但是并不是所有的东西都可以变成不可变的,所以到目前为止还远远不够。
因此,只要我们想要某种有用的东西,Cremain就会提供一种令人愉悦的语言,但是当我们想要一种始终安全地起作用的东西时,便会令人沮丧。
Java更加令人沮丧,因为它具有与C#相同的问题,并且更多:缺少与C#的using
关键字等效的代码,我的一个非常熟练的同事花了太多时间来确保正确释放其资源,而在Java中等效C ++很容易(使用析构函数和智能指针)。
因此,我想对于大多数代码来说C#/ Java的生产率提高都是可见的……直到我们需要使代码尽可能完美的那一天。那天,你会知道痛苦的。 (我们不会相信我们的服务器和GUI应用程序的要求...)。
关于服务器端Java和C ++
我在大楼的另一侧与服务器团队保持联系(在返回GUI团队之前,我在其中工作了2年),并且学到了一些有趣的东西。
去年,趋势是注定要用Java服务器应用程序替换旧的C ++服务器应用程序,因为Java有很多框架/工具,并且易于维护,部署等。
...直到低延迟的问题在过去的几个月里抬起了头。然后,无论我们熟练的Java团队尝试进行哪种优化,Java服务器应用程序都干净利落地失去了与未经过优化的旧C ++服务器的竞争。
当前,决策是将Java服务器保留在性能仍然很重要的情况下使用,而低延迟目标却不关心它,并积极地优化已经更快的C ++服务器应用程序以满足低延迟和超低延迟的需求。
总结
没有什么比预期的那么简单。
Java,甚至更多的C#,都是很酷的语言,具有广泛的标准库和框架,我们可以在其中快速编码,并很快就能得到结果。
但是,当我们需要原始能力,强大而系统的优化,强大的编译器支持,强大的语言功能以及绝对的安全性时,Java和C很难赢得我们需要保持在竞争水平之上的最后缺失但至关重要的质量百分比。
似乎与C ++相比,用C#/ Java花费更少的时间和更少的经验的开发人员来生成平均质量的代码,但是,另一方面,当我们需要出色的完美质量的代码时,突然变得更容易,更快地获得结果。就在C ++中
当然,这是我自己的看法,也许仅限于我们的特定需求。
但是,无论今天在GUI团队还是在服务器端团队中,这都是今天发生的事情。
当然,如果发生新情况,我将更新这篇文章。
编辑(2011-06-22)
"We find that in regards to performance, C++ wins out by a large margin. However, it also required the most extensive tuning efforts, many of which were done at a level of sophistication that would not be available to the average programmer. [...] The Java version was probably the simplest to implement, but the hardest to analyze for performance. Specifically the effects around garbage collection were complicated and very hard to tune."
资料来源:
- https://days2011.scala-lang.org/sites/days2011/files/ws3-1-Hundt.pdf
- http://www.computing.co.uk/ctg/news/2076322/-winner-google-language-tests
编辑(2011-09-20)
"The going word at Facebook is that 'reasonably written C++ code just runs fast,' which underscores the enormous effort spent at optimizing PHP and Java code. Paradoxically, C++ code is more difficult to write than in other languages, but efficient code is a lot easier [to write in C++ than in other languages]." – Herb Sutter at //build/, quoting Andrei Alexandrescu
资料来源:
- http://channel9.msdn.com/Events/BUILD/BUILD2011/TOOL-835T
- http://video.ch9.ms/build/2011/slides/TOOL-835T_Sutter.pptx
如果我们是学习C ++的Java / C程序员,那么我们会很想继续使用Java / C进行思考,并将逐字转换为C ++语法。在这种情况下,我们只能获得前面提到的本机代码与解释型/ JIT相比的好处。为了在C ++与Java / C#中获得最大的性能提升,我们必须学习在C ++中进行思考,并专门设计代码以利用C ++的优势。
用埃德斯·迪克斯特拉(Edsger Dijkstra)的话来解释:[第一语言]残缺了无法康复的思想。
用杰夫·阿特伍德(Jeff Atwood)来解释:我们可以用任何新语言写[第一语言]。
用于特定CPU优化的编译通常被高估了。只需使用C ++编写一个程序,然后针对pentium PRO进行优化编译并在奔腾4上运行。然后针对pentium 4进行优化进行重新编译。我花了很长时间来完成几个程序。一般结果??通常性能提升不到2-3%。因此,理论上的JIT优势几乎没有。大多数性能差异仅在使用标量数据处理功能时才能观察到,而最终需要手动进行微调以达到最佳性能。这种优化的执行速度缓慢且成本高昂,因此有时仍然不适合JIT。
在现实世界和实际应用程序中,C ++通常仍比Java快,这主要是因为内存占用量更少,从而导致更好的缓存性能。
但是要使用所有C ++功能,开发人员必须努力工作。我们可以取得优异的成绩,但是我们必须为此动脑筋。 C ++是一种决定为我们提供更多工具的语言,收取一定的费用,我们必须学习这些工具才能很好地使用该语言。
这是一个有趣的基准
http://zi.fi/shootout/
每当我谈论托管性能与非托管性能时,我都想指出Rico(和Raymond)所做的系列比较了中英文字典的C ++和Cversions。这个Google搜索会让我们自己阅读,但是我喜欢Rico的摘要。
So am I ashamed by my crushing defeat? Hardly. The managed code got a very good result for hardly any effort. To defeat the managed Raymond had to: Write his own file I/O stuff Write his own string class Write his own allocator Write his own international mapping Of course he used available lower level libraries to do this, but that's still a lot of work. Can you call what's left an STL program? I don't think so, I think he kept the std::vector class which ultimately was never a problem and he kept the find function. Pretty much everything else is gone. So, yup, you can definately beat the CLR. Raymond can make his program go even faster I think. Interestingly, the time to parse the file as reported by both programs internal timers is about the same -- 30ms for each. The difference is in the overhead.
对我而言,最重要的是,非托管版本花了6个修订版才击败了托管版本,而托管版本是原始非托管代码的简单移植。如果我们需要性能的最后一点(并且有时间和专业知识来获得),则必须不受管理,但是对我来说,我将采用第一个版本在33之上的数量级优势。如果尝试6次,我会有所收获。
实际上,C并没有像Java那样在虚拟机中真正运行。 IL被编译为汇编语言,该语言完全是本机代码,并且以与本机代码相同的速度运行。我们可以对.NET应用程序进行预JIT,这将完全消除JIT成本,然后我们将运行完全本机代码。
.NET变慢的原因不是因为.NET代码更慢,而是因为它在后台执行了很多工作,如垃圾收集,检查引用,存储完整的堆栈框架等。这在执行时会非常强大并且很有帮助。构建应用程序,但也要付出一定的代价。请注意,我们也可以在C ++程序中完成所有这些操作(许多核心.NET功能实际上是.NET代码,我们可以在ROTOR中查看)。但是,如果我们手工编写了相同的功能,由于.NET运行时已经过优化和微调,因此最终程序可能会慢得多。
也就是说,托管代码的优势之一是它可以完全验证。我们可以在执行代码之前验证该代码永远不会访问其他进程的内存或者对它们进行不明智的操作。微软拥有一个完全托管操作系统的研究原型,令人惊讶地表明,通过利用此验证来关闭托管程序不再需要的安全功能,一个100%托管环境实际上可以比任何现代操作系统执行显着更快的运行。 (在某些情况下,我们的谈话速度是10倍)。 SE电台在谈论这个项目时有一段精彩的插曲。
我也不知道...我的Java程序总是很慢。 :-)不过,我从来没有真正注意到C程序的运行速度特别慢。
实际上,Sun的HotSpot JVM使用"混合模式"执行。它解释该方法的字节码,直到确定(通常通过某种计数器)某个特定的代码块(方法,循环,try-catch块等)将要执行很多,然后JIT对其进行编译。 JIT编译方法所需的时间通常比该方法很少运行时要解释的时间要长。通常,"混合模式"的性能会更高,因为JVM不会浪费时间来很少(如果有的话)运行的JITing代码。
Cand .NET不这样做。 .NET JIT经常浪费时间。
最重要的JIT优化之一是方法内联。如果Java能保证运行时正确性,它甚至可以内联虚拟方法。这种优化通常不能由标准的静态编译器执行,因为它需要对整个程序进行分析,而由于要进行单独的编译,因此很难(与之相反,JIT拥有所有可用的程序)。方法内联改进了其他优化,提供了更大的代码块进行优化。
Java / Ci中的标准内存分配也更快,并且释放(GC)不会慢很多,但是确定性却很少。
这是另一个有趣的基准,我们可以在自己的计算机上尝试一下。
它比较了ASM,VC ++,C#,Silverlight,Java applet,Javascript,Flash(AS3)
Roozz插件速度演示
请注意,JavaScript的速度变化很大,具体取决于执行该浏览器的浏览器。 Flash和Silverlight的情况也是如此,因为这些插件与托管浏览器的运行过程相同。但是Roozz插件运行标准的.exe文件,这些文件以自己的进程运行,因此速度不受托管浏览器的影响。
这是克里夫(Cliff)的答案:http://www.azulsystems.com/blog/cliff/2009-09-06-java-vs-c-performance再次
我们应该定义"性能优于.."。好吧,我知道,我们问的是速度,但它并不是至关重要的。
- 虚拟机是否执行更多的运行时开销?是的!
- 他们会吃更多的工作记忆吗?是的!
- 它们是否具有较高的启动成本(运行时初始化和JIT编译器)?是的!
- 他们需要安装巨大的库吗?是的!
依此类推,这是有偏见的,是;)
使用Cand Java,我们需要为获得的一切付出代价(更快的编码,自动内存管理,大型库等)。但是我们没有太多余地来讨价还价:拿完整的包裹或者什么都不做。
即使那些语言可以优化某些代码以使其比编译后的代码执行得更快,但整个方法仍然无效(IMHO)。想象一下,每天用卡车开车到工作场所5英里!它舒适,感觉良好,很安全(极端的压溃区),踩油门一段时间后,它的速度甚至可以和标准车一样快!为什么我们所有人都没有卡车开车上班? ;)
在C ++中,我们得到的是所付出的,而不是更多,更少。
引用Bjarne Stroustrup的话:" C ++是我最喜欢的垃圾收集语言,因为它产生的垃圾很少"
连结文字
对于需要大量速度的任何事物,JVM只是调用C ++实现,因此,与大多数操作系统相关的事情相比,JVM的性能要好得多是一个问题。
垃圾回收会将内存减少一半,但是使用一些更高级的STL和Boost功能将具有相同的效果,但潜在的错误几倍。
如果我们仅在具有多个类的大型项目中使用C ++库及其许多高级功能,则可能会比使用JVM慢。除了更容易出错以外。
但是,C ++的好处是它允许我们优化自己,否则我们将被编译器/ jvm所困扰。如果我们创建自己的容器,编写自己的对齐的内存管理,使用SIMD,然后到处组装,则可以比大多数C ++编译器自行完成的速度提高至少2到4倍。对于某些操作,为16x-32x。那就是使用相同的算法,如果我们使用更好的算法并进行并行化,则增长可能会非常惊人,有时会比常用方法快数千倍。
我从几个不同的角度来看它。
- 在无限的时间和资源下,托管或者非托管代码会更快吗?显然,答案是非托管代码在这方面总是至少可以绑定托管代码-在最坏的情况下,我们只是对托管代码解决方案进行硬编码。
- 如果我们以一种语言来学习程序,然后直接将其翻译为另一种语言,那么它的性能会降低多少?对于任何两种语言,可能很多。大多数语言需要不同的优化并具有不同的陷阱。微观性能通常与了解这些细节有关。
- 在有限的时间和资源下,两种语言中的哪一种会产生更好的结果?这是最有趣的问题,因为尽管托管语言生成的代码可能会稍微慢一些(考虑到合理地为该语言编写的程序),但该版本可能会更快地完成,从而将更多时间花在优化上。
一个简短的答案:在固定预算的情况下,与C ++应用程序相比,我们将获得性能更好的Java应用程序(考虑到ROI)。此外,Java平台具有更完善的分析器,可更快地确定热点
阅读有关HP Labs的Dynamo(Dynamo)的知识,这是一种在PA-8000上运行的PA-8000解释器,并且其运行程序的速度通常比其本机运行的速度快。那就一点也不奇怪了!
不要将其视为"中间步骤"-运行程序已经涉及许多其他步骤,无论使用哪种语言。
通常可以归结为:
- 程序具有热点,因此,即使我们在运行95%的代码主体时运行得较慢,但在5%的情况下运行得更快,我们仍然可以在性能上保持竞争力
- HLL比C / C ++等LLL更了解意图,因此可以生成更优化的代码(OCaml甚至更多,并且在实践中通常更快)
- JIT编译器具有很多静态编译器没有的信息(例如,我们这次恰好拥有的实际数据)
- JIT编译器可以在运行时进行传统链接器实际上不允许执行的优化(例如对分支进行重新排序,以使常见情况变得平淡无奇,或者内联库调用)
总而言之,C / C ++的性能很差劲:关于数据类型的信息很少,没有关于数据的信息,也没有动态运行时,从而无法进行很多运行时优化。
当Java或者CLR比C ++快时,我们可能会突然爆发,但总体而言,性能会降低应用程序的寿命:
有关某些结果,请参见www.codeproject.com/KB/dotnet/RuntimePerformance.aspx。