C ++性能与Java / C#
我的理解是C / C ++生成本地代码以在特定的机器体系结构上运行。 相反,像Java和C#这样的语言运行在一个抽象出本地体系结构的虚拟机之上。 从逻辑上讲,由于这个中间步骤,Java或C#似乎不可能匹配C ++的速度,但是我被告知最新的编译器(“热点”)可以达到这个速度甚至超过它。
也许这更像是一个编译问题,而不是一个语言问题,但任何人都可以用简单的英语来解释这些虚拟机语言之一是否可能比本地语言更好地执行?
一般来说,C#和Java可以同样快或者更快,因为JIT编译器(一个在第一次执行时编译你的IL的编译器)可以优化C ++编译的程序,因为它可以查询机器。 它可以确定机器是Intel还是AMD; Pentium 4,Core Solo或Core Duo; 或者如果支持SSE4等
一个C ++程序必须事先通过混合优化进行编译,这样它才能在所有机器上运行得很好,但没有像单个configuration(即处理器,指令集和其他硬件)那样优化。
此外,某些语言特性允许C#和Java中的编译器对您的代码进行假设,使其能够优化某些部分,而这些部分对于C / C ++编译器来说是不安全的。 当你访问指针时,有很多优化是不安全的。
另外,Java和C#可以比C ++更有效地进行堆分配,因为垃圾收集器和代码之间的抽象层允许它一次完成所有的堆压缩(相当昂贵的操作)。
现在我不能在下一点上谈论Java,但是我知道C#例如在知道方法体是空的时候实际上会删除方法和方法调用。 它将在整个代码中使用这种逻辑。
正如你所看到的,为什么某些C#或Java实现会更快,有很多原因。
现在这一切都表示,可以在C ++中进行特定的优化,这将会吹走C#所能做的任何事情,特别是在graphics领域以及任何接近硬件的领域。 指针在这里创造奇迹。
所以根据你写的内容,我会select其中一个。 但是如果你写的东西不是硬件相关的(驱动程序,video游戏等),我不会担心C#的性能(再也不能谈论Java)。 它会做得很好。
一个是Java方面, @Swati指出了一个好文章:
JIT与静态编译器
正如前面的文章所述,JIT可以在运行时将IL /字节码编译为本地代码。 提到的成本,但不是结论:
JIT有一个巨大的问题是它不能编译所有的东西:JIT编译需要时间,所以JIT将只编译代码的一部分,而静态编译器会生成一个完整的本地二进制文件:对于某些types的程序,静态编译器将简单地胜过JIT。
当然,C#(或者Java,或者VB)通常比C ++生成可行且健壮的解决scheme要快得多(因为C ++具有复杂的语义,而C ++标准库虽然有趣而强大,但与完整从.NET或Java开始的标准库的范围),所以通常,C ++和.NET或Java JIT之间的区别对于大多数用户来说是不可见的,对于那些关键的二进制文件,你仍然可以调用C ++处理从C#或Java(即使这种本地调用本身可能是相当昂贵的)…
C ++元编程
请注意,通常,您将C ++运行时代码与其在C#或Java中的等效代码进行比较。 但是C ++有一个function可以超越Java / C#的开箱即用,就是模板元编程:代码处理将在编译时完成(因此增加了大量的编译时间),导致运行时为零(或几乎为零)。
我还没有看到真正的生活效果(我只玩概念,不过到那时,差别是JIT的执行时间和C ++的零 ),但这是值得一提的,除了事实模板元编程不是不重要的…
编辑2011-06-10:在C ++中,玩types是在编译时完成的,意思是生成调用非generics代码的generics代码(例如,从string到Ttypes的genericsparsing器,为它所识别的types调用标准库API,并使得parsing器易于被用户扩展)非常简单而且非常高效,而Java或C#中的等价物在写入时是痛苦的,即使在编译时已知types,这意味着你唯一的希望就是让JIT把整个事情联系起来。
…
编辑2011-09-20: Blitz ++( 主页 , 维基百科 )背后的团队走的是这样,显然,他们的目标是通过C ++模板元编程尽可能地从运行时执行到编译时间,以达到FORTRAN在科学计算上的performance。 所以 上面写的那部分 “我看到了真实的生活效果”显然确实存在于现实生活中。
本地C ++内存使用情况
C ++具有不同于Java / C#的内存使用,因此具有不同的优点/缺陷。
不pipeJIT的优化如何,没有任何东西会像指向内存的直接访问那样快(让我们忽略一下处理器caching等等)。 所以,如果你在内存中有连续的数据,通过C ++指针(即C指针…让Caesar到期)访问会比在Java / C#中快几倍。 而且C ++有RAII,这使得大量的处理比C#甚至Java更容易。 C ++不需要using
范围的对象的存在。 而C ++没有finally
子句。 这不是一个错误。
🙂
尽pipeC#是基本的结构,C ++“堆栈”对象在分配和销毁时不会花费任何代价,并且不需要GC在独立线程中进行清理。
至于内存碎片,2008年的内存分配器不是从1980年开始通常与GC相比的旧的内存分配器:C ++的分配不能在内存中移动,不过,就像在Linux文件系统上一样:谁需要硬盘碎片没有发生时进行碎片整理? 为正确的任务使用正确的分配器应该是C ++开发人员工具箱的一部分。 现在,编写分配器并不容易,然后我们大多数人都有更好的事情去做,对于大部分的使用来说,RAII或者GC都不够好。
编辑2011-10-04:有关高效分配器的示例:在Windows平台上,自Vista以来, 低碎片堆默认情况下处于启用状态。 对于以前的版本,可以通过调用WinAPI函数HeapSetInformation来激活LFH。 在其他操作系统上,提供了替代分配器(请参阅https://secure.wikimedia.org/wikipedia/en/wiki/Malloc获取列表);
现在,随着多核和multithreading技术的兴起,内存模型变得越来越复杂。 在这个领域,我认为.NET有优势,据我所知,Java占据了上风。 一些“裸机”黑客很容易称赞他的“机器附近”代码。 但是现在,编制更好的汇编比编译器的工作更困难。 对于C ++,自十年以来,编译器通常比黑客更好。 对于C#和Java,这更容易。
尽pipe如此,新的标准C ++ 0x将为C ++编译器强加一个简单的内存模型,这将在C ++中标准化(并因此简化)有效的多处理/并行/线程代码,并使编译器的优化更容易和更安全。 但是,接下来几年我们会看到它的承诺是否真实。
C ++ / CLI与C#/ VB.NET
注意:在本节中,我正在讨论C ++ / CLI,即.NET托pipe的C ++,而不是本机C ++。
上周,我对.NET优化进行了一次培训,发现静态编译器非常重要。 和JIT一样重要。
在C ++ / CLI(或其祖先,Managed C ++)中编译的相同代码可能比在C#中生成的代码(或VB.NET,其编译器生成的C#相同的IL)快得多。
因为C ++静态编译器比C#更好地生成已经优化的代码。
例如,.NET中的函数内联仅限于字节码小于或等于32字节的函数。 因此,C#中的一些代码将生成一个40字节的访问器,这将不会被JIT内联。 在C ++ / CLI中相同的代码将产生一个20字节的访问器,它将被JIT内联。
另一个例子是临时variables,它们被C ++编译器简单地编译掉,而在C#编译器生成的IL中仍然被提及。 C ++静态编译优化将导致更less的代码,从而再次授权更积极的JIT优化。
之所以被推测是C ++ / CLI编译器从C ++本地编译器的大量优化技术中获益的原因。
结论
我喜欢C ++。
但就我所见,C#或Java都是更好的select。 并不是因为它们比C ++更快,而是因为当你把自己的特质加起来的时候,他们最终会变得更有效率,需要更less的培训,并且拥有比C ++更完整的标准库。 而对于大多数程序,他们的速度差异(以这种或那种方式)将可以忽略不计…
编辑(2011-06-06)
我在C#/。NET上的经验
我现在已经有了5个月的专业C#编程(这已经使我的CV已经充满了C ++和Java,还有一些C ++ / CLI)。
我使用了WinForms(Ahem …)和WCF(cool!)以及WPF(Cool !!!!都是通过XAML和原始C#,WPF非常简单,我相信Swing只是无法与之相提并论)和C#4.0。
结论是,尽pipe生成一个在C#/ Java中比在C ++中工作的代码更容易/更快,但在C#中生成强壮,安全和健壮的代码(甚至在Java中更困难)比C ++更困难。 原因比比皆是,但可以总结为:
- generics不如模板强大 ( 尝试编写一个高效的通用Parse方法(从string到T),或者在C#中使用boost :: lexical_cast来有效地理解问题 )
- RAII仍然是无与伦比的 ( GC仍然可以泄漏(是的,我必须处理这个问题)并且只能处理内存,即使C#的
using
也不是那么容易和强大,因为编写正确的Dispose实现是困难的 ) - C#
readonly
和Javafinal
都不如C ++的const
有用 ( 在C#中,没有办法可以暴露只读的复杂数据(例如,Tree of Nodes),而它是C ++的一个内置特性。一个有趣的解决scheme,但并不是所有东西都可以做到不可改变,所以远远不够 )。
所以,只要你想要一些有用的东西,C#仍然是一个令人愉快的语言,但是当你想要一些总是安全的东西的时候,C语言是令人沮丧的语言。
Java更令人沮丧,因为它具有与C#相同的问题,还有更多: using
关键字缺lessC#的等价物,我的一个非常熟练的同事花费了太多的时间来确保它的资源在正确释放的地方,而C ++中的等价物会很容易(使用析构函数和智能指针)。
所以我想大多数代码都可以看到C#/ Java的生产力增长……直到你需要代码尽可能完美为止。 那一天,你会知道痛苦。 (你不会相信我们的服务器和GUI应用程序要求什么…)。
关于服务器端Java和C ++
我和服务器团队保持联系(我从事了两年的工作,然后回到了GUI团队),在大楼的另一边,我学到了一些有趣的东西。
去年,趋势是Java服务器应用程序将注定要replace旧的C ++服务器应用程序,因为Java有许多框架/工具,易于维护,部署等。
…直到低延迟的问题在最后几个月才出现了丑陋的头脑。 然后,Java服务器应用程序,不pipe我们熟练的Java团队所尝试的优化如何,简单而干净地失去了与旧的,没有真正优化的C ++服务器的竞争。
目前,决定是保持Java服务器的通用性,而性能仍然是重要的,不受低延迟目标的影响,并积极地优化已经更快的C ++服务器应用程序以实现低延迟和超低延迟需求。
结论
没有什么比预期的简单。
Java,甚至更多的C#,都是很酷的语言,有着广泛的标准库和框架,你可以快速编写代码,并且很快就会有结果。
但是,当你需要原始的力量,强大而系统的优化,强大的编译器支持,强大的语言特性以及绝对的安全性时,Java和C#使得难以赢得你需要保持在竞争对手之上的最后一个缺失但关键的质量百分比。
就像在C#/ Java中比在C ++中需要更less的时间和更less的经验的开发人员来产生平均质量的代码,但另一方面,当你需要优秀的代码来完善高质量的代码时,得到结果突然变得更容易和更快在C ++中。
当然,这是我自己的看法,也许只限于我们的具体需求。
但是,现在在GUI团队和服务器端团队中都是如此。
当然,如果有新事发生,我会更新这个post。
编辑(2011-06-22)
“我们发现,在性能方面,C ++大幅度胜出,但是它也需要最广泛的调优工作,其中很多都是在普通程序员无法提供的高级水平上完成的。
Java版本可能是最简单的实现,但最难分析性能。 垃圾收集的效果特别复杂,很难调整。“
资料来源:
- sites/days2011/files/ws3-1-Hundt.pdf
- http://www.computing.co.uk/ctg/news/2076322/-winner-google-language-tests
编辑(2011-09-20)
“Facebook上正在写的一句话就是” 合理编写的C ++代码运行得很快 “,这强调了在优化PHP和Java代码方面花费的大量精力。相反,C ++代码比其他语言更难编写,但高效的代码是比使用其他语言编写C ++更容易。 “
– 香草萨特在/ /build立 ,引用安德烈Alexandrescu
资料来源:
每当我谈论托pipe性能和非托pipe性能时,我都喜欢指出Rico(和Raymond)系列比较C ++和C#版本的中文/英文字典。 这谷歌search将让你自己阅读,但我喜欢里科的总结。
所以我为自己惨败而感到羞耻? 几乎不。 托pipe代码几乎没有任何努力,取得了很好的结果。 打败pipe理雷蒙德不得不:
- 写他自己的文件I / O的东西
- 写他自己的string类
- 写他自己的分配器
- 写他自己的国际映射
当然,他使用可用的低级库来做到这一点,但这仍然是一个很大的工作。 你可以调用什么是一个STL程序? 我不这么认为,我认为他保留了std :: vector类,它最终从来不是一个问题,他保留了find函数。 几乎一切都消失了。
所以,你可以肯定地击败CLR。 雷蒙德可以让他的节目更快,我想。
有趣的是,两个程序内部定时器报告的parsing文件的时间大致相同 – 每个30ms。 不同之处在于开销。
对我来说,底线是非托pipe版本花了6个版本来击败原始非托pipe代码的简单端口的托pipe版本。 如果你需要最后一点的performance(并且有时间和专业知识才能获得),那么你将不得不不受pipe理,但是对于我来说,我将在33如果我尝试6次,我就会获益。
特定CPU优化的编译通常被高估。 只需要用C ++编写一个程序,然后在pentium PRO上进行优化,然后在奔腾4上运行。然后在pentium 4中进行优化重新编译。我用几个程序通过了很长的一个下午。 一般结果? 通常性能提升不到2-3%。 所以理论上的JIT优势几乎没有。 只有在使用标量数据处理function时才能观察到大多数性能差异,而最终需要手动调整才能实现最佳性能。 无论如何,这种优化的执行速度缓慢且代价高昂,使得它们有时不适合JIT。
在现实世界和真正的应用程序中,C ++通常比java更快,主要是因为内存占用更less,导致更好的caching性能。
但要使用所有的C ++function,开发人员必须努力工作。 你可以取得优异的成绩,但是你必须用你的大脑。 C ++是一门决定向你展示更多工具的语言,收取你必须学习的价格,才能够很好地使用语言。
JIT(即时编译)可以非常快速,因为它优化了目标平台。
这意味着它可以利用CPU可以支持的任何编译器技巧,而不pipe开发者在哪个CPU上编写代码。
.NET JIT的基本概念就像这样(非常简化):
第一次调用方法:
- 你的程序代码调用一个方法Foo()
- CLR查看实现Foo()的types并获取与其关联的元数据
- 从元数据中,CLR知道存储IL(中间字节码)的存储器地址。
- CLR分配一块内存,并调用JIT。
- JIT将IL编译为本地代码,将其放入分配的内存中,然后将Foo()的types元数据中的函数指针更改为指向此本机代码。
- 本机代码已经运行。
第二次调用方法:
- 你的程序代码调用一个方法Foo()
- CLR查看实现Foo()的types并在元数据中find函数指针。
- 该内存位置的本地代码已经运行。
正如你所看到的,第二次,除了具有实时优化的优点以外,它几乎与C ++一样。
也就是说,还有其他pipe理语言的开销问题,但JIT帮助很大。
我喜欢猎户座阿德里安的答案,但还有另一个方面。
几十年前,关于汇编语言与“人类”语言(如FORTRAN)的问题也提出了同样的问题。 部分答案是相似的。
是的,C ++程序在任何给定的(非平凡的)algorithm上都比C#更快,但是C#中的程序通常比C ++中的“天真”实现更快或更快,并且C ++中的优化版本将需要更长的时间来开发,并且可能仍然以很小的幅度击败C#版本。 那么,真的值得吗?
你必须逐个回答这个问题。
也就是说,我是C ++的忠实粉丝,我认为这是一个令人难以置信的expression力和强大的语言 – 有时候被低估了。 但是,在许多“现实生活”问题上(对我个人而言,这意味着“我付钱解决的那种”),C#将会更快,更安全地完成工作。
你付的最大的惩罚是? 许多.NET和Java程序都是内存占用。 我曾经见过.NET和Java应用程序需要“数百”兆字节的内存,而类似复杂性的C ++程序几乎不能抓取“十几个”MB。
我不知道多久你会发现Java代码运行速度比C ++快,即使是使用Hotspot,但是我会仔细研究它是如何发生的。
将编译的Java代码视为JVM的解释机器语言。 当热点处理器注意到编译代码的某些部分将被多次使用时,它会对机器代码进行优化。 由于手动debugging汇编程序几乎总是比C ++编译代码快,因此可以用编程的方式来确定 – 调整好的机器代码不会太糟糕。
因此,对于高度重复的代码,我可以看到Hotspot JVM能够比C ++更快地运行Java,直到垃圾收集发挥作用。 🙂
通常,程序的algorithm对于应用程序的速度比语言要重要得多。 你可以用任何语言实现一个糟糕的algorithm,包括C ++。 考虑到这一点,通常可以用一种语言编写运行代码,以帮助您实现更高效的algorithm。
更高级的语言在这方面做得非常好,通过提供更容易访问许多高效的预build数据结构和鼓励实践来帮助您避免低效的代码。 当然,他们有时也可以很容易地编写一堆非常慢的代码,所以你仍然需要知道你的平台。
此外,C ++正在赶上“新”(注意引号)function,如STL容器,自动指针等 – 例如参见boost库。 而且你可能偶尔会发现,完成某个任务的最快方法需要像高级语言中禁止的指针算术这样的技术 – 虽然它们通常允许你用一种可以按照需要实现的语言来调用一个库。
主要的是知道你正在使用的语言,它是相关的API,它可以做什么,它的限制是什么。
我也不知道…我的Java程序总是很慢。 :-)我从来没有真正注意到C#程序特别慢,但。
这里还有另外一个基准testing,你可以在自己的电脑上试试自己。
它比较了ASM,VC ++,C#,Silverlight,Java applet,Javascript,Flash(AS3)
Roozz插件速度演示
请注意,JavaScript的速度取决于浏览器正在执行它的很多变化。 对于Flash和Silverlight也是如此,因为这些插件与托pipe浏览器在同一个进程中运行。 但Roozz插件运行标准的.exe文件,这些文件在自己的进程中运行,因此速度不受托pipe浏览器的影响。
你应该定义“比…更好的performance”。 那么,我知道,你问速度,但不是所有的重要。
- 虚拟机执行更多的运行时间开销吗? 是!
- 他们是否吃更多的工作记忆? 是!
- 他们有更高的启动成本(运行时初始化和JIT编译器)? 是!
- 他们需要安装一个庞大的图书馆吗? 是!
等等,它是有偏见的,是的;)
使用C#和Java,您可以付出代价(更快的编码,自动内存pipe理,大型库等)。 但你没有太多的空间讨论细节:采取完整的包装或没有任何东西。
即使这些语言可以优化一些代码来执行比编译代码更快,整个方法是(恕我直言)低效率。 想象一下,每天驾驶5英里到工作场所,用卡车! 它舒适,感觉很好,你是安全的(极端折皱区),在你踩了一段时间之后,它甚至会像标准车一样快! 为什么我们不都有一辆卡车开车上class? ;)
在C ++中,你得到了你所支付的,而不是更多,而不是更less。
引用Bjarne Stroustrup:“C ++是我最喜欢的垃圾回收语言,因为它产生了很less的垃圾” 链接文本
从Java或C#编译器生成的可执行代码不被解释 – 它被编译为本地代码“即时”(JIT)。 因此,Java / C#程序中的第一次代码在执行期间遇到,由于“运行时编译器”(又名JIT编译器)将字节代码(Java)或IL代码(C#)转换为本机机器指令,因此会有一些开销。 但是,下次在应用程序仍在运行时遇到代码时,将立即执行本机代码。 这就解释了一些Java / C#程序在开始的时候似乎很慢,但是运行时间越长,性能越好。 一个很好的例子是一个ASP.Net网站。 网站第一次被访问时,它可能会慢一些,因为JIT编译器将C#代码编译为本地代码。 随后的访问导致更快的网站 – 服务器端和客户端caching。
这里有一些关于你问的具体问题的很好的答案。 我想退后一步,看看更大的图景。
请记住,用户对您所编写软件的速度的感受受许多其他因素的影响,而不仅仅是codegen优化的程度。 这里有些例子:
-
手动内存pipe理很难做到正确(没有泄漏),甚至很难有效地完成(在完成之后很快就会释放内存)。 使用GC通常更有可能产生一个pipe理内存的程序。 你是否愿意努力工作,并拖延交付你的软件,试图超越GC?
-
我的C#比我的C ++更容易阅读和理解。 我也有更多的方式说服自己,我的C#代码工作正常。 这意味着我可以优化我的algorithm,避免引入错误的风险(并且用户不喜欢软件崩溃,即使它很快就会崩溃!)
-
我可以在C#中比在C ++中更快地创build我的软件。 这样可以腾出时间来处理性能问题,并能够按时交付我的软件。
-
在C#中编写好的用户界面要比用C ++编写起来更容易,所以我更有可能在UI保持响应的时候将工作推到后台,或者在程序不得不阻塞一段时间时提供进度或者听力用户界面。 这不会让任何事情变得更快,但它会让用户更高兴地等待。
我所说的关于C#的所有内容对于Java来说都可能是真实的,我只是没有经验可以肯定地说。
如果您是一名学习C ++的Java / C#程序员,那么您将不断思考Java / C#,并逐字逐句转换为C ++语法。 在这种情况下,你只能得到本机代码与解释/ JIT早先提到的好处。 为了在C ++和Java / C#中获得最大的性能提升,你必须学会用C ++思考,并专门devise代码来利用C ++的优势。
解释Edsger Dijkstra :[你的第一语言]将思维切割得无法恢复。
为了解释杰夫·阿特伍德(Jeff Atwood) :你可以用任何新的语言来写[你的第一语言]。
最重要的JIT优化之一是方法内联。 Java甚至可以内联虚拟方法,如果它可以保证运行时的正确性。 这种优化通常不能由标准的静态编译器来完成,因为它需要全程序分析,这是由于单独编译而难以实现的(相反,JIT拥有所有可用的程序)。 方法内联改进了其他优化,给予更大的代码块进行优化。
Java / C#中的标准内存分配速度也更快,并且释放(GC)速度也不会太慢,但是确定性较低。
The virtual machine languages are unlikely to outperform compiled languages but they can get close enough that it doesn't matter, for (at least) the following reasons (I'm speaking for Java here since I've never done C#).
1/ The Java Runtime Environment is usually able to detect pieces of code that are run frequently and perform just-in-time (JIT) compilation of those sections so that, in future, they run at the full compiled speed.
2/ Vast portions of the Java libraries are compiled so that, when you call a library function, you're executing compiled code, not interpreted. You can see the code (in C) by downloading the OpenJDK.
3/ Unless you're doing massive calculations, much of the time your program is running, it's waiting for input from a very slow (relatively speaking) human.
4/ Since a lot of the validation of Java bytecode is done at the time of loading the class, the normal overhead of runtime checks is greatly reduced.
5/ At the worst case, performance-intensive code can be extracted to a compiled module and called from Java (see JNI) so that it runs at full speed.
In summary, the Java bytecode will never outperform native machine language, but there are ways to mitigate this. The big advantage of Java (as I see it) is the HUGE standard library and the cross-platform nature.
Orion Adrian , let me invert your post to see how unfounded your remarks are, because a lot can be said about C++ as well. And telling that Java/C# compiler optimize away empty functions does really make you sound like you are not my expert in optimization, because a) why should a real program contain empty functions, except for really bad legacy code, b) that is really not black and bleeding edge optimization.
Apart from that phrase, you ranted blatantly about pointers, but don't objects in Java and C# basically work like C++ pointers? May they not overlap? May they not be null? C (and most C++ implementations) has the restrict keyword, both have value types, C++ has reference-to-value with non-null guarantee. What do Java and C# offer?
>>>>>>>>>>
Generally, C and C++ can be just as fast or faster because the AOT compiler — a compiler that compiles your code before deployment, once and for all, on your high memory many core build server — can make optimizations that a C# compiled program cannot because it has a ton of time to do so. The compiler can determine if the machine is Intel or AMD; Pentium 4, Core Solo, or Core Duo; or if supports SSE4, etc, and if your compiler does not support runtime dispatch, you can solve for that yourself by deploying a handful of specialized binaries.
AC# program is commonly compiled upon running it so that it runs decently well on all machines, but is not optimized as much as it could be for a single configuration (ie processor, instruction set, other hardware), and it must spend some time first. Features like loop fission, loop inversion, automatic vectorization, whole program optimization, template expansion, IPO, and many more, are very hard to be solved all and completely in a way that does not annoy the end user.
Additionally certain language features allow the compiler in C++ or C to make assumptions about your code that allows it to optimize certain parts away that just aren't safe for the Java/C# compiler to do. When you don't have access to the full type id of generics or a guaranteed program flow there's a lot of optimizations that just aren't safe.
Also C++ and C do many stack allocations at once with just one register incrementation, which surely is more efficient than Javas and C# allocations as for the layer of abstraction between the garbage collector and your code.
Now I can't speak for Java on this next point, but I know that C++ compilers for example will actually remove methods and method calls when it knows the body of the method is empty, it will eliminate common subexpressions, it may try and retry to find optimal register usage, it does not enforce bounds checking, it will autovectorize loops and inner loops and will invert inner to outer, it moves conditionals out of loops, it splits and unsplits loops. It will expand std::vector into native zero overhead arrays as you'd do the C way. It will do inter procedural optimmizations. It will construct return values directly at the caller site. It will fold and propagate expressions. It will reorder data into a cache friendly manner. It will do jump threading. It lets you write compile time ray tracers with zero runtime overhead. It will make very expensive graph based optimizations. It will do strength reduction, were it replaces certain codes with syntactically totally unequal but semantically equivalent code (the old "xor foo, foo" is just the simplest, though outdated optimization of such kind). If you kindly ask it, you may omit IEEE floating point standards and enable even more optimizations like floating point operand re-ordering. After it has massaged and massacred your code, it might repeat the whole process, because often, certain optimizations lay the foundation for even certainer optimizations. It might also just retry with shuffled parameters and see how the other variant scores in its internal ranking. And it will use this kind of logic throughout your code.
So as you can see, there are lots of reasons why certain C++ or C implementations will be faster.
Now this all said, many optimizations can be made in C++ that will blow away anything that you could do with C#, especially in the number crunching, realtime and close-to-metal realm, but not exclusively there. You don't even have to touch a single pointer to come a long way.
So depending on what you're writing I would go with one or the other. But if you're writing something that isn't hardware dependent (driver, video game, etc), I wouldn't worry about the performance of C# (again can't speak about Java). It'll do just fine.
<<<<<<<<<<
Generally, certain generalized arguments might sound cool in specific posts, but don't generally sound certainly credible.
Anyways, to make peace: AOT is great, as is JIT . The only correct answer can be: It depends. And the real smart people know that you can use the best of both worlds anyways.
It would only happen if the Java interpreter is producing machine code that is actually better optimized than the machine code your compiler is generating for the C++ code you are writing, to the point where the C++ code is slower than the Java and the interpretation cost.
However, the odds of that actually happening are pretty low – unless perhaps Java has a very well-written library, and you have your own poorly written C++ library.
Actually, C# does not really run in a virtual machine like Java does. IL is compiled into assembly language, which is entirely native code and runs at the same speed as native code. You can pre-JIT an .NET application which entirely removes the JIT cost and then you are running entirely native code.
The slowdown with .NET will come not because .NET code is slower, but because it does a lot more behind the scenes to do things like garbage collect, check references, store complete stack frames, etc. This can be quite powerful and helpful when building applications, but also comes at a cost. Note that you could do all these things in a C++ program as well (much of the core .NET functionality is actually .NET code which you can view in ROTOR). However, if you hand wrote the same functionality you would probably end up with a much slower program since the .NET runtime has been optimized and finely tuned.
That said, one of the strengths of managed code is that it can be fully verifiable, ie. you can verify that the code will never access another processes's memory or do unsage things before you execute it. Microsoft has a research prototype of a fully managed operating system that has suprisingly shown that a 100% managed environment can actually perform significantly faster than any modern operating system by taking advantage of this verification to turn off security features that are no longer needed by managed programs (we are talking like 10x in some cases). SE radio has a great episode talking about this project.
In some cases, managed code can actually be faster than native code. For instance, "mark-and-sweep" garbage collection algorithms allow environments like the JRE or CLR to free large numbers of short-lived (usually) objects in a single pass, where most C/C++ heap objects are freed one-at-a-time.
From wikipedia :
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.
That said, I've written a lot of C# and a lot of C++, and I've run a lot of benchmarks. In my experience, C++ is a lot faster than C#, in two ways: (1) if you take some code that you've written in C#, port it to C++ the native code tends to be faster. 快多less? Well, it varies a whole lot, but it's not uncommon to see a 100% speed improvement. (2) In some cases, garbage collection can massively slow down a managed application. The .NET CLR does a terrible job with large heaps (say, > 2GB), and can end up spending a lot of time in GC–even in applications that have few–or even no–objects of intermediate life spans.
Of course, in most cases that I've encounted, managed languages are fast enough, by a long shot, and the maintenance and coding tradeoff for the extra performance of C++ is simply not a good one.
Here's an interesting benchmark http://zi.fi/shootout/
Actually Sun's HotSpot JVM uses "mixed-mode" execution. It interprets the method's bytecode until it determines (usually through a counter of some sort) that a particular block of code (method, loop, try-catch block, etc.) is going to be executed a lot, then it JIT compiles it. The time required to JIT compile a method often takes longer than if the method were to be interpreted if it is a seldom run method. Performance is usually higher for "mixed-mode" because the JVM does not waste time JITing code that is rarely, if ever, run. C# and .NET do not do this. .NET JITs everything which, often times, wastes time.
Go read about HP Labs' Dynamo , an interpreter for PA-8000 that runs on PA-8000, and often runs programs faster than they do natively. Then it won't seem at all surprising!
Don't think of it as an "intermediate step" — running a program involves lots of other steps already, in any language.
It often comes down to:
-
programs have hot-spots, so even if you're slower running 95% of the body of code you have to run, you can still be performance-competitive if you're faster at the hot 5%
-
a HLL knows more about your intent than a LLL like C/C++, and so can generate more optimized code (OCaml has even more, and in practice is often even faster)
-
a JIT compiler has a lot of information that a static compiler doesn't (like, the actual data you happen to have this time)
-
a JIT compiler can do optimizations at run-time that traditional linkers aren't really allowed to do (like reordering branches so the common case is flat, or inlining library calls)
All in all, C/C++ are pretty lousy languages for performance: there's relatively little information about your data types, no information about your data, and no dynamic runtime to allow much in the way of run-time optimization.
You might get short bursts when Java or CLR is faster than C++, but overall the performance is worse for the life of the application: see http://www.codeproject.com/KB/dotnet/RuntimePerformance.aspx for some results for that.
Here is answer from Cliff Click: http://www.azulsystems.com/blog/cliff/2009-09-06-java-vs-c-performanceagain
My understanding is that C/C++ produces native code to run on a particular machine architecture. Conversely, languages like Java and C# run on top of a virtual machine which abstracts away the native architecture. Logically it would seem impossible for Java or C# to match the speed of C++ because of this intermediate step, however I've been told that the latest compilers ("hot spot") can attain this speed or even exceed it.
That is illogical. The use of an intermediate representation does not inherently degrade performance. For example, llvm-gcc compiles C and C++ via LLVM IR (which is a virtual infinite-register machine) to native code and it achieves excellent performance (often beating GCC).
Perhaps this is more of a compiler question than a language question, but can anyone explain in plain English how it is possible for one of these virtual machine languages to perform better than a native language?
这里有些例子:
-
Virtual machines with JIT compilation facilitate run-time code generation (eg
System.Reflection.Emit
on .NET) so you can compile generated code on-the-fly in languages like C# and F# but must resort to writing a comparatively-slow interpreter in C or C++. For example, to implement regular expressions. -
Parts of the virtual machine (eg the write barrier and allocator) are often written in hand-coded assembler because C and C++ do not generate fast enough code. If a program stresses these parts of a system then it could conceivably outperform anything that can be written in C or C++.
-
Dynamic linking of native code requires conformance to an ABI that can impede performance and obviates whole-program optimization whereas linking is typically deferred on VMs and can benefit from whole-program optimizations (like .NET's reified generics).
I'd also like to address some issues with paercebal's highly-upvoted answer above (because someone keeps deleting my comments on his answer) that presents a counter-productively polarized view:
The code processing will be done at compilation time…
Hence template metaprogramming only works if the program is available at compile time which is often not the case, eg it is impossible to write a competitively performant regular expression library in vanilla C++ because it is incapable of run-time code generation (an important aspect of metaprogramming).
…playing with types is done at compile time…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.
In C#, that is only true of reference types and is not true for value types.
No matter the JIT optimization, nothing will go has fast as direct pointer access to memory…if you have contiguous data in memory, accessing it through C++ pointers (ie C pointers… Let's give Caesar its due) will goes times faster than in Java/C#.
People have observed Java beating C++ on the SOR test from the SciMark2 benchmark precisely because pointers impede aliasing-related optimizations.
Also worth noting that .NET does type specialization of generics across dynamically-linked libraries after linking whereas C++ cannot because templates must be resolved before linking. And obviously the big advantage generics have over templates is comprehensible error messages.
On top of what some others have said, from my understanding .NET and Java are better at memory allocation. Eg they can compact memory as it gets fragmented while C++ cannot (natively, but it can if you're using a clever garbage collector).
For anything needing lots of speed, the JVM just calls a C++ implementation, so it's a question more of how good their libs are than how good the JVM is for most OS related things. Garbage collection cuts your memory in half, but using some of the fancier STL and Boost features will have the same effect but with many times the bug potential.
If you are just using C++ libraries and lots of its high level features in a large project with many classes you will probably wind up slower than using a JVM. Except much more error prone.
However, the benefit of C++ is that it allows you to optimize yourself, otherwise you are stuck with what the compiler/jvm does. If you make your own containers, write your own memory management that's aligned, use SIMD, and drop to assembly here and there, you can speed up at least 2x-4x times over what most C++ compilers will do on their own. For some operations, 16x-32x. That's using the same algorithms, if you use better algorithms and parallelize, increases can be dramatic, sometimes thousands of times faster that commonly used methods.
I look at it from a few different points.
- Given infinite time and resources, will managed or unmanaged code be faster? Clearly, the answer is that unmanaged code can always at least tie managed code in this aspect – as in the worst case, you'd just hard-code the managed code solution.
- If you take a program in one language, and directly translate it to another, how much worse will it perform? Probably a lot, for any two languages. Most languages require different optimizations and have different gotchas. Micro-performance is often a lot about knowing these details.
- Given finite time and resources, which of two languages will produce a better result? This is the most interesting question, as while a managed language may produce slightly slower code (given a program reasonably written for that language), that version will likely be done sooner, allowing for more time spent on optimization.
A very short answer: Given a fixed budget you will achieve better performing java application than a C++ application (ROI considerations) In addition Java platform has more decent profilers, that will help you pinpoint your hotspots more quickly