C + + 性能对比 Java/C #

我的理解是,C/C + + 生成的本机代码可以运行在特定的机器架构上。相反,像 Java 和 C # 这样的语言是在虚拟机上运行的,虚拟机抽象出了本机体系结构。从逻辑上讲,Java 或 C # 似乎不可能达到 C + + 的速度,因为这是一个中间步骤,但是我被告知,最新的编译器(“热点”)可以达到甚至超过这个速度。

也许这更多的是一个编译器问题而不是语言问题,但是有人能够用简单的英语解释一下这些虚拟机器语言中的一种如何能够比本地语言表现得更好吗?

438511 次浏览

只有当 Java 解释器生成的机器代码实际上比你的编译器生成的 C + + 代码的机器代码 好多了优化时,这种情况才会发生,以至于 C + + 代码比 Java 和解释成本更慢。

然而,实际发生这种情况的可能性非常低——除非 Java 有一个编写得非常好的库,并且您有自己的编写得非常糟糕的 C + + 库。

Generally, C# and Java can be just as fast or faster because the JIT compiler -- a compiler that compiles your IL the first time it's executed -- can make optimizations that a C++ compiled program cannot because it can query the machine. It can determine if the machine is Intel or AMD; Pentium 4, Core Solo, or Core Duo; or if supports SSE4, etc.

一个 C + + 程序必须事先进行编译,通常需要进行混合优化,这样它才能在所有机器上运行良好,但是对于单个配置(即处理器、指令集和其他硬件) ,它的优化程度还不够。

此外,某些语言特性允许 C # 和 Java 中的编译器对代码做出假设,从而允许它优化掉某些对 C/C + + 编译器来说不安全的部分。当您访问指针时,会有很多不安全的优化。

Java 和 C # 也可以比 C + + 更有效地进行堆分配,因为垃圾收集器和代码之间的抽象层允许它一次完成所有的堆压缩(这是一个相当昂贵的操作)。

现在我不能代表 Java 说下一点,但是我知道,例如,当 C # 知道方法体为空时,它实际上会删除方法和方法调用。它将在整个代码中使用这种逻辑。

因此,正如您所看到的,有很多原因可以解释为什么某些 C # 或 Java 实现会更快。

现在这一切都说明,特定的优化可以在 C + + 中进行,这将吹走任何你可以用 C # 做的事情,特别是在图形领域和任何时候你接近硬件。指针在这里能创造奇迹。

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.

在 Java 方面,@ Swati指出了一篇好文章:

Https://www.ibm.com/developerworks/library/j-jtp09275

Java 或 C # 编译器生成的可执行代码不会被解释——它被编译成“及时”(JIT)的本机代码。因此,Java/C # 程序中的第一次代码是在执行过程中遇到的,当“运行时编译器”(又名 JIT 编译器)将字节码(Java)或 IL 代码(C #)转换成本地机器指令时,会有一些开销。但是,下次在应用程序仍在运行时遇到该代码时,将立即执行本机代码。这解释了为什么一些 Java/C # 程序最初看起来很慢,但是运行的时间越长,性能就越好。ASP.Net 网站就是一个很好的例子。在第一次访问网站时,可能会稍慢一些,因为 C # 代码是由 JIT 编译器编译成本机代码的。随后的访问导致更快的网站——服务器端和客户端缓存暂且不提。

On top of what some others have said, from my understanding .NET and Java are better at memory allocation. E.g. they can compact memory as it gets fragmented while C++ cannot (natively, but it can if you're using a clever garbage collector).

虚拟机语言的性能不太可能超过编译语言,但是它们可以足够接近编译语言,所以这并不重要,原因(至少)如下(我在这里代表 Java 说话,因为我从来没有做过 C #)。

1/JRE 通常能够检测频繁运行的代码片段,并对这些片段执行即时(just-in-time,JIT)编译,以便将来它们能以全速运行。

2/大量的 Java 库被编译,当你调用一个库函数时,你正在执行已编译的代码,而不是解释。您可以通过下载 OpenJDK 查看代码(C 语言)。

3/除非你正在做大量的计算,否则你的程序大部分时间都在运行,它在等待一个非常慢(相对而言)的人类输入。

4/由于 Java 字节码的许多验证都是在装入类时完成的,因此运行时检查的正常开销大大降低。

5/在最坏的情况下,性能密集型代码可以被提取到一个已编译的模块中,并从 Java 中调用(参见 JNI) ,这样它就可以全速运行了。

总之,Java 字节码的性能永远不会超过本地机器语言,但是有一些方法可以减轻这种情况。Java 的最大优点(我认为)是 HUGE标准库和跨平台的特性。

我不确定你会多久发现 Java 代码比 C + + 运行得更快,即使是使用 Hotspot,但是我会解释它是如何发生的。

可以将编译的 Java 代码看作 JVM 的解释机器语言。当 Hotspot 处理器注意到某些已编译代码将被多次使用时,它将对机器代码执行优化。由于手工调优 Assembly 几乎总是比 C + + 编译的代码快,所以可以认为经过编程调优的机器代码不会比 也是差。

因此,对于高度重复的代码,我可以看到 Hotspot JVM 在哪些地方可以比 C + + 更快地运行 Java... ... 直到垃圾收集开始发挥作用。:)

JIT (即时编译)可以非常快,因为它针对目标平台进行了优化。

这意味着它可以利用 CPU 可以支持的任何编译器技巧,而不管开发人员在哪个 CPU 上编写代码。

.NET JIT 的基本概念是这样工作的(经过大量简化) :

第一次调用方法:

  • 程序代码调用方法 Foo ()
  • CLR 查看实现 Foo ()的类型并获取与之关联的元数据
  • 通过元数据,CLR 知道 IL (中间字节码)存储在哪个内存地址中。
  • CLR 分配一块内存,并调用 JIT。
  • JIT 将 IL 编译成本机代码,将其放入分配的内存中,然后更改 Foo ()的类型元数据中的函数指针以指向这个本机代码。
  • The native code is ran.

第二次调用方法:

  • 程序代码调用方法 Foo ()
  • CLR 查看实现 Foo ()的类型并在元数据中找到函数指针。
  • The native code at this memory location is ran.

正如您所看到的,第二次,除了具有实时优化的优点之外,它实际上与 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.

也就是说,我已经编写了大量的 C # 和 C + + ,并运行了大量的基准测试。根据我的经验,C + + 比 C # 快得多,有两个方面: (1)如果你用 C # 写了一些代码,把它移植到 C + + ,本地代码 往往会更快。多快?虽然变化很大,但速度提高100% 并不罕见。(2)在某些情况下,垃圾收集可以 非常严重减慢托管应用程序的速度。那个。NET CLR 在处理大堆(比如,> 2GB)方面做得很糟糕,最终可能会在 GC 中花费大量时间——即使是在中间生命周期对象很少(甚至没有)的应用程序中。

当然,在我遇到的大多数情况下,托管语言都足够快,远远不够,而维护和编码对 C + + 额外性能的折衷并不好。

一般来说,程序的 算法对于应用程序的速度要比 language重要得多。你可以用任何语言实现一个很差的算法,包括 C + + 。考虑到这一点,您通常能够用一种语言更快地编写代码,从而帮助您实现更有效的算法。

高级语言在这方面做得很好,它提供了对许多有效的预构建数据结构的更容易的访问,并鼓励有助于避免低效代码的实践。当然,有时候它们也可以让编写一堆非常慢的代码变得非常容易,因此您仍然需要了解自己的平台。

此外,C + + 正在迎头赶上“ new”(注意引号)特性,比如 STL 容器、自动指针等等——例如,参见升级库。你可能偶尔会发现,完成某些任务的最快方法需要一种技术,比如在高级语言中禁止使用的指针算法——尽管它们通常允许你调用用一种语言编写的库,这种语言可以根据需要实现它。

主要的事情是要知道你使用的语言,它是相关的 API,它可以做什么,它的局限性是什么。

Some good answers here about the specific question you asked. I'd like to step back and look at the bigger picture.

Keep in mind that your user's perception of the speed of the software you write is affected by many other factors than just how well the codegen optimizes. Here are some examples:

  • 手动内存管理很难正确完成(没有泄漏) ,更难有效完成(完成后很快释放内存)。一般来说,使用 GC 更有可能生成一个能够很好地管理内存的程序。您是否愿意非常努力地工作,并推迟交付软件,试图超越 GC?

  • 我的 C # 比 C + + 更容易阅读和理解。我也有更多的方法来说服自己我的 C # 代码工作正常。这意味着我可以在引入 bug 的风险较小的情况下优化我的算法(而且用户不喜欢崩溃的软件,即使它崩溃得很快!)

  • 我可以用 C # 比用 C + + 更快地创建我的软件。这样就可以腾出时间来进行性能方面的工作,并且仍然可以按时交付我的软件。

  • 用 C # 编写优秀的 UI 比用 C + + 更容易,所以我更有可能在 UI 保持响应时将工作推到后台,或者在程序需要阻塞一段时间时提供进度或心跳 UI。这不会让任何事情变得更快,但是它会让用户更乐于等待。

我所说的关于 C # 的一切对于 Java 来说可能都是正确的,只是我没有足够的经验来确定。

我喜欢 Orion Adrian的答案,但它还有另一个方面。

几十年前,汇编语言和 FORTRAN 这样的“人类”语言之间也出现了同样的问题。部分答案是相似的。

是的,一个 C + + 程序在任何给定的情况下都能比 C # 更快(非常重要?)但是 C # 中的程序通常会和 C + + 中的“幼稚”实现一样快或者更快,而且 C + + 中的优化版本将花费更长的时间来开发,并且仍然可能以非常小的差距击败 C # 版本。真的值得吗?

你必须逐一回答这个问题。

也就是说,我是 C + + 的长期粉丝,我认为它是一种极具表现力和强大功能的语言——有时被低估了。但是在许多“现实生活”问题中(对我个人来说,这意味着“我得到报酬来解决的那种”) ,C # 将更快更安全地完成工作。

The biggest penalty you pay? Many .NET and Java programs are memory hogs. I have seen .NET and Java apps take "hundreds" of megabytes of memory, when C++ programs of similar complexity barely scratch the "tens" of MBs.

JIT 与静态编译器

正如在前面的文章中已经说过的,JIT 可以在运行时将 IL/字节码编译成本机代码。报告提到了这样做的代价,但没有得出结论:

JIT 有一个很大的问题,它不能编译所有的东西: JIT 编译需要时间,所以 JIT 只会编译代码的一部分,而静态编译器会产生完整的本机二进制文件: 对于某些程序,静态编译器的性能很容易超过 JIT。

当然, C # (或 Java, 或 VB)通常比 C + + 更快地产生可行和健壮的解决方案(如果只是因为 C + + 有复杂的语义, 和 C++标准程式库, 虽然有趣和强大, 是相当差的标准库的全范围相比, 从。NET 或 Java) ,所以通常情况下,C + + 和。NET 或 Java JIT 对于大多数用户来说是不可见的,对于那些关键的二进制文件,你仍然可以从 C # 或 Java 调用 C + + 处理(即使这种本地调用本身可能非常昂贵) ..。

C + + 元编程

请注意,通常您将 C + + 运行时代码与 C # 或 Java 中的等效代码进行比较。但是 C + + 有一个特性可以胜过 Java/C # 开箱即用,那就是模板元编程: 代码处理将在编译时完成(因此大大增加了编译时间) ,导致运行时为零(或几乎为零)。

我已经看到了现实生活中对此的影响(我只玩概念,但到那时,不同之处在于 JIT 的执行时间是几秒钟,而 C + + 的执行时间是 ) ,但是值得一提的是,与此同时,模板元编程并不是微不足道的..。

编辑2011-06-10: 在 C + + 中,对类型的处理是在编译时完成的,这意味着生成调用非通用代码的通用代码(例如,一个从字符串到类型 T 的通用解析器,调用标准库 API 来识别类型 T,并使解析器容易被用户扩展)是非常容易和非常有效的,而 Java 或 C # 中的等价物在编写时最多是痛苦的,即使在编译时知道类型,在运行时也总是更慢和解析,这意味着你唯一的 希望 < i > 是 JIT 内联整个事情。

...

编辑2011-09-20: Blitz + + (HomepageWikipedia)背后的团队走的是这条路,显然,他们的目标是通过 C + + 模板超编程尽可能多地从运行时执行到编译时间,从而达到 FORTRAN 在科学计算方面的表现。所以上面我写的“我已经看到了一个真实的生活效果”部分显然 是的存在于现实生活中。

本机 C + + 内存使用

C + + 的内存使用不同于 Java/C # ,因此有不同的优点/缺陷。

无论 JIT 优化如何,没有什么比直接指针访问内存更快(让我们暂时忽略处理器缓存等)。因此,如果内存中有连续数据,那么通过 C + + 指针(即 C 指针... ... 让我们给凯撒应得的权限)访问它的速度要比 Java/C # 快几倍。而且 C + + 有 RAII,这使得很多处理过程比 C # 甚至 Java 都要简单得多。C + + 不需要 using来确定其对象的存在范围。C + + 没有 finally子句。这不是错误。

:-)

尽管有 C # 原语式的结构,“在堆栈上”的 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) https://secure.wikimedia.org/wikipedia/en/wiki/malloc 获得列表)

现在,随着多核和多线程技术的兴起,内存模型变得更加复杂。我想是在这个领域吧。NET 有优势,而 Java,我被告知,占据上风。对于一些“赤裸裸的金属”黑客来说,赞美他的“靠近机器”的代码是很容易的。但是现在,手工生成更好的汇编要比让编译器完成它的工作困难得多。对于 C + + 来说,十年来编译器通常比黑客做得更好。对于 C # 和 Java 来说,这就更简单了。

尽管如此,新的标准 C + + 0x 将为 C + + 编译器强加一个简单的内存模型,这将标准化(从而简化) C + + 中有效的多处理/并行/线程代码,并使编译器的优化更容易、更安全。但是,我们将在几年后看到它的承诺是否兑现。

C + +/CLI 与 C #/VB.NET

注意: 在本节中,我将讨论 C + +/CLI,即. NET 托管的 C + + ,而不是本机 C + + 。

Last week, I had a training on .NET optimization, and discovered that the static compiler is very important anyway. As important than JIT.

用 C + +/CLI 编译的同样的代码(或者它的祖先,Managed C + +)可能比用 C # 编译的同样的代码(或者用 VB.NET,它的编译器产生的 IL 与 C # 相同)快几倍。

因为 C + + 静态编译器在生成已经优化的代码方面比 C # 要好得多。

例如,函数内联在。NET 仅限于字节码长度小于或等于32字节的函数。因此,C # 中的一些代码将产生一个40字节的访问器,这将永远不会被 JIT 内联。C + +/CLI 中的相同代码将生成一个20字节的访问器,该访问器将由 JIT 内联。

另一个例子是临时变量,它们被 C + + 编译器简单地编译掉,同时仍然在 C # 编译器生成的 IL 中被提及。C + + 静态编译优化将导致更少的代码,从而再次授权更积极的 JIT 优化。

原因可能是 C + +/CLI 编译器从 C + + 本机编译器的大量优化技术中获益。

结论

我喜欢 C + + 。

但在我看来,C # 或 Java 都是更好的选择。不是因为它们比 C + + 更快,而是因为当你把它们的质量加起来,它们最终会变得更高效,需要更少的培训,并且拥有比 C + + 更完整的标准库。对于大多数程序来说,它们的速度差异(以这样或那样的方式)将是可以忽略不计的..。

编辑(2011-06-06)

我在 C #/. NET 上的体验

我现在已经有5个月几乎独占的专业 C # 编码经验(这加起来已经是我的履历中充满了 C + + 和 Java,还有一点 C + +/CLI)。

我玩 WinForms (咳咳...)和 WCF (酷!)和 WPF (酷! ! ! !通过 XAML 和原始 C # 。WPF 是如此简单,我相信 Swing 无法与之相比) ,以及 C # 4.0。

结论是,尽管在 C #/Java 中编写代码比在 C + + 中更容易/更快,但在 C # 中编写强大、安全和健壮的代码要比在 C + + 中难得多(在 Java 中甚至更难)。原因很多,但可以归纳如下:

  1. Generics are not as powerful as templates (尝试编写一个高效的通用 Parse 方法(从字符串到 T) ,或者在 C # 中编写一个高效的等价形式 ost: : lexical _ cast 来理解问题)
  2. RAII 仍然不匹配 (GC 仍然可能泄漏(是的,我必须处理这个问题) ,并且只能处理内存。甚至 C # 的 using也没有这么简单和强大,因为编写正确的 Dispose 实现很困难)
  3. C # readonly和 Java final没有 C + + 的 const (在 C # 中公开只读复杂数据(例如节点树)需要大量的工作,而这是 C + + 的一个内置特性。不可变数据是一个有趣的解决方案,但不是所有东西都可以变成不可变的,所以到目前为止,这还不够)那么有用。

所以,只要你想要一种可以工作的语言,C # 仍然是一种令人愉快的语言,但是当你想要一种 永远安全可以工作的语言时,C # 就成了一种令人沮丧的语言。

Java 甚至更令人沮丧,因为它有着与 C # 相同的问题,而且还有更多: 缺乏与 C # 的 using关键字等价的东西,我的一个非常熟练的同事花了太多时间确保它的资源在正确释放的地方,而 C + + 中的等价物本来会很容易(使用析构函数和智能指针)。

所以我猜 C #/Java 的生产力提高对于大多数代码来说是可见的... ... 直到有一天你需要代码尽可能完美。那一天,你会知道痛苦。(你不会相信我们的服务器和 GUI 应用程序提出了什么要求...)。

关于服务器端 Java 和 C + +

我与大楼另一边的服务器团队保持联系(在回到 GUI 团队之前,我在他们中间工作了2年) ,我学到了一些有趣的东西。

去年的趋势是,Java 服务器应用程序注定要取代旧的 C + + 服务器应用程序,因为 Java 有很多框架/工具,并且易于维护、部署等等。.

直到最近几个月低延迟问题出现。然后,Java 服务器应用程序,无论我们熟练的 Java 团队尝试了多少优化,都干净利落地输掉了与老式的、没有真正优化的 C + + 服务器的竞赛。

Currently, the decision is to keep the Java servers for common use where performance while still important, is not concerned by the low-latency target, and aggressively optimize the already faster C++ server applications for low-latency and ultra-low-latency needs.

结论

Nothing is as simple as expected.

Java,甚至更多的 C # ,都是很酷的语言,拥有大量的标准库和框架,在这些语言中你可以快速编码,并且很快就会有结果。

But when you need raw power, powerful and systematic optimizations, strong compiler support, powerful language features and absolute safety, Java and C# make it difficult to win the last missing but critical percents of quality you need to remain above the competition.

It's as if you needed less time and less experienced developers in C#/Java than in C++ to produce average quality code, but in the other hand, the moment you needed excellent to perfect quality code, it was suddenly easier and faster to get the results right in C++.

当然,这是我个人的看法,也许仅限于我们的具体需要。

但是,无论是在 GUI 团队还是在服务器端团队中,这仍然是今天发生的事情。

当然,如果有新的事情发生,我会更新这篇文章。

编辑(2011-06-22)

“我们发现,在性能方面,C + + 赢得了 但是,它也需要最广泛的 tuning efforts, many of which were done at a level of sophistication 普通程序员无法使用的。

Java 版本可能是实现起来最简单的,但是性能分析起来却是最困难的。特别是垃圾收集的影响非常复杂,很难调整。”

资料来源:

编辑(2011-09-20)

“ Facebook 的流行语是‘ 合理编写的 C + + 代码运行得很快,’,它强调了在优化 PHP 和 Java 代码方面所付出的巨大努力。自相矛盾的是,C + + 代码比其他语言更难写,但是 efficient code is a lot easier [to write in C++ than in other languages].

Herb Sutter at 建造, quoting 返回文章页面【 Andrei Alexandrescu 】亚历山大 · 雷斯库译者:

资料来源:

If you're a Java/C# programmer learning C++, you'll be tempted to keep thinking in terms of Java/C# and translate verbatim to C++ syntax. In that case, you only get the earlier mentioned benefits of native code vs. interpreted/JIT. To get the biggest performance gain in C++ vs. Java/C#, you have to learn to think in C++ and design code specifically to exploit the strengths of C++.

Edsger Dijkstra的话来说就是: (你的第一语言)会使你的思想无法恢复。
解释一下 杰夫 · 阿特伍德: 你可以用任何一种新的语言来写[你的母语]。

针对特定 CPU 优化的编译通常被高估了。只需用 C + + 编写一个程序,用奔腾 PRO 进行优化编译,然后在奔腾4上运行。然后为奔腾4重新编译并进行优化。我花了好几个下午的时间和几个节目一起做这件事。一般结果? ?性能提升通常小于2-3% 。因此,理论上的 JIT 优势几乎为零。大多数性能差异只能在使用标量数据处理特性时才能观察到,这些特性最终将需要手动微调才能实现最大的性能。这种类型的优化执行起来既缓慢又昂贵,因此有时不适合 JIT。

在现实世界和实际应用程序中,C + + 通常仍然比 Java 快,这主要是因为内存占用更少,从而带来更好的缓存性能。

但是要使用所有的 C + + 能力你,开发人员必须努力工作。你可以获得更好的结果,但是你必须用你的大脑来做到这一点。C + + 是一种决定向您提供更多工具的语言,收取的费用是您必须学习它们才能很好地使用该语言。

这里有一个有趣的基准 Http://zi.fi/shootout/

每当我谈到托管和非托管性能时,我都喜欢指出 Rico (和 Raymond)在比较中英文字典的 C + + 和 C # 版本时所做的系列。这个 google search会让你自己阅读,但我喜欢里科的总结。

我为自己的惨败感到羞愧吗? 几乎没有。托管代码得到了一个非常 对于几乎没有任何努力的好结果 雷蒙德不得不:

  • Write his own file I/O stuff
  • Write his own string class
  • 自己编写分配器
  • 自己写国际地图

当然他用的是可用的更低的 水平库做到这一点,但这是 还有很多工作要做,你能打电话 什么是剩下的 STL 程序? 我不知道 think so, I think he kept the 向量类,它最终是 从来没有问题,他保持了发现 function. Pretty much everything else 消失了。

所以,没错,你绝对可以打败 雷蒙德可以让他的程序运行 甚至更快。

有趣的是,解析 file as reported by both programs internal timers is about the same -- 每个30毫秒,差别在于 开销。

For me the bottom line is that it took 6 revisions for the unmanaged version to beat the managed version that was a simple port of the original unmanaged code. If you need every last bit of performance (and have the time and expertise to get it), you'll have to go unmanaged, but for me, I'll take the order of magnitude advantage I have on the first versions over the 33% I gain if I try 6 times.

实际上,C # 并不像 Java 那样在虚拟机中运行。IL 被编译成汇编语言,汇编语言完全是本机代码,运行速度与本机代码相同。你可以提前准备。NET 应用程序,它完全消除了 JIT 成本,然后您运行的是完全本机代码。

减速。NET 不会来,因为。NET 代码比较慢,但是因为它在后台做了很多事情,比如垃圾收集、检查引用、存储完整的堆栈帧等等。这在构建应用程序时可能非常强大和有帮助,但是也需要付出代价。请注意,您也可以在 C + + 程序中完成所有这些事情(核心的大部分)。NET 的功能实际上是。可以在 ROTOR 中查看的 NET 代码)。然而,如果您手工编写相同的功能,那么您可能最终会得到一个慢得多的程序,因为。NET 运行时已经进行了优化和微调。

也就是说,托管代码的优势之一是它可以完全验证,即。您可以验证代码在执行之前永远不会访问其他进程的内存或执行 unage 操作。微软有一个完全管理的操作系统的研究原型,令人惊讶地表明一个100% 管理的环境实际上可以比任何现代操作系统执行得更快,利用这种验证关闭不再需要的安全功能的管理程序(我们正在讨论在某些情况下10倍)。SE 电台有一个伟大的插曲谈论这个项目。

我也不知道... ... 我的 Java 程序总是很慢。 : :)不过,我从来没有真正注意到 C # 程序特别慢。

实际上 Sun 的 HotSpot JVM 使用“混合模式”执行。它解释方法的字节码,直到它确定(通常通过某种计数器)某个特定的代码块(方法、循环、 try-catch 块等)要大量执行,然后 JIT 编译它。JIT 编译一个方法所需的时间通常比解释一个很少运行的方法所需的时间要长。对于“混合模式”,性能通常更高,因为 JVM 不会浪费很少运行的 JIT 代码的时间。 C # 和.NET 不这样做. NET JIT 的一切,往往是浪费时间。

One of the most significant JIT optimizations is method inlining. Java can even inline virtual methods if it can guarantee runtime correctness. This kind of optimization usually cannot be performed by standard static compilers because it needs whole-program analysis, which is hard because of separate compilation (in contrast, JIT has all the program available to it). Method inlining improves other optimizations, giving larger code blocks to optimize.

Standard memory allocation in Java/C# is also faster, and deallocation (GC) is not much slower, but only less deterministic.

下面是另一个有趣的基准测试,您可以在自己的计算机上进行测试。

比较了 ASM、 VC + + 、 C # 、 Silverlight、 Javaapplet、 Javascript、 Flash (AS3)

Roozz 插件速度演示

Please note that the speed of javascript varries a lot depending on what browser is executing it. The same is true for Flash and Silverlight because these plugins run in the same process as the hosting browser. But the Roozz plugin run standard .exe files, which run in their own process, thus the speed is not influenced by the hosting browser.

你应该定义“表现好于. .”。好吧,我知道,你问速度,但它不是一切都重要。

  • 虚拟机是否执行更多的运行时开销? 是的!
  • 他们吃更多的工作记忆吗? 是的!
  • 它们有更高的启动成本(运行时初始化和 JIT 编译器)吗? 是的!
  • 它们需要安装一个巨大的库吗? 是的!

诸如此类,它是有偏见的,是的;)

使用 C # 和 Java,你需要为你所得到的付出代价(更快的编码、自动内存管理、大型库等等)。但你没有太多的空间来讨价还价的细节: 采取完整的一揽子或没有。

Even if those languages can optimize some code to execute faster than compiled code, the whole approach is (IMHO) inefficient. Imagine driving every day 5 miles to your workplace, with a truck! Its comfortable, it feels good, you are safe (extreme crumple zone) and after you step on the gas for some time, it will even be as fast as a standard car! Why don't we all have a truck to drive to work? ;)

在 C + + 中,你得到的是你花钱买的东西,而不是更多,而不是更少。

引用比雅尼·斯特劳斯特鲁普: “ c + + 是我最喜欢的垃圾收集语言,因为它产生的垃圾太少了。” 链接文本

对于任何需要大量速度的东西,JVM 只调用 C + + 实现,所以问题更多的是它们的库有多好,而不是 JVM 对于大多数与操作系统相关的东西有多好。 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.

如果您只是在一个有许多类的大型项目中使用 C + + 库和它的许多高级特性,那么您可能会比使用 JVM 慢一些。只是更容易出错。

然而,C + + 的好处在于它允许您优化自己,否则您将被困在编译器/jvm 所做的工作中。如果你制作自己的容器,编写自己的对齐的内存管理,使用 SIMD,到处进行汇编,你至少可以比大多数 C + + 编译器自己的速度提高2-4倍。对于某些操作,16x-32x。这是使用相同的算法,如果你使用更好的算法和并行化,增加可以是戏剧性的,有时比常用的方法快几千倍。

我从几个不同的角度来看。

  1. 给定无限的时间和资源,托管或非托管代码是否会更快?显然,非托管代码至少可以在这方面绑定托管代码——在最坏的情况下,您只需硬编码托管代码解决方案。
  2. 如果你用一种语言编写一个程序,然后直接翻译成另一种语言,它的性能会差到什么程度呢?可能很多,对于 任何两种语言来说。大多数语言需要不同的优化,并有不同的陷阱。微观表现往往与了解这些细节有很大关系。
  3. 给定有限的时间和资源,两种语言中哪一种会产生更好的结果?这是最有趣的问题,因为虽然托管语言可能会产生稍慢的代码(给定一个为该语言编写的程序) ,但该版本可能会更快完成,从而允许在优化上花费更多的时间。

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

Go read about HP Labs' 发电机, 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!

不要认为它是一个“中间步骤”——运行一个程序已经涉及到许多其他步骤,在任何语言中都是如此。

这通常可以归结为:

  • 程序有热点,所以即使你运行的代码体的95% 运行得比较慢,如果你在热点的5% 运行得比较快,你仍然可以在性能上具有竞争力

  • HLL 比 C/C + + 这样的 LL 更了解您的意图,因此可以生成更优化的代码(OCaml 的代码更多,实际上通常更快)

  • JIT 编译器拥有许多静态编译器所没有的信息(比如,这次碰巧拥有的实际数据)

  • JIT 编译器可以在运行时执行传统链接器实际上不允许执行的优化(比如重新排序分支以使通用情况是平的,或者内联库调用)

总而言之,C/C + + 在性能方面是相当糟糕的语言: 关于数据类型的信息相对较少,没有关于数据的信息,也没有动态运行时来支持运行时优化。

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: 看看 www.codeproject.com/kb/dotnet/runtimeperformance.aspx 的结果吧。

Orion Adrian ,让我把你的帖子倒过来看看你的评论是多么没有根据,因为 C + + 也可以说很多东西。告诉 Java/C # 编译器优化去除空函数确实让你听起来像是我的优化专家,因为 a)为什么一个真正的程序应该包含空函数,除了非常糟糕的遗留代码,b)这真的不是黑色和前沿优化。

除了这句话,您还公然抨击了指针,但是 Java 和 C # 中的对象不是基本上像 C + + 指针一样工作吗?它们可以不重叠吗?它们可能不是无效的吗?C (和大多数 C + + 实现)都有限制关键字,都有值类型,C + + 有引用到值和非空保证。Java 和 C # 提供什么?

>>>>>>>>>>

一般来说,C 和 C + + 可以同样快或者更快,因为 AOT 编译器——一个在部署之前编译你的代码的编译器,一劳永逸地,在你的高内存许多核心构建服务器上——可以进行 C # 编译程序所不能进行的优化,因为它有大量的时间来这样做。编译器可以判断机器是 Intel 还是 AMD; Pentium 4、 Core Solo 还是 Core Duo; 或者是否支持 SSE4等等,如果你的编译器不支持运行时分派,你可以通过部署一些专门的二进制文件来解决这个问题。

一个 C # 程序通常是在运行的时候编译的,这样它在所有机器上都能很好地运行,但是对于单个配置(例如处理器、指令集、其他硬件)来说,它并没有得到足够的优化,而且它首先要花一些时间在 must上。诸如循环裂变、循环反转、自动矢量化、整体程序优化、模板扩展、首次公开募股等等,这些特性都很难在不惹恼终端用户的情况下完全解决。

此外,某些特定的语言特性允许 C + + 或 C 中的编译器对代码做出假设,从而允许它对 Java/C # 编译器不安全的特定部分进行优化。当您不能访问泛型的完整类型 id 或者一个有保证的程序流时,就会有很多不安全的优化。

同样,C + + 和 C 只需要一个寄存器增量就可以同时进行多个堆栈分配,这对于垃圾收集器和代码之间的抽象层来说,肯定比 Java 和 C # 分配更有效率。

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.

因此,正如您所看到的,有很多原因可以解释为什么某些 C + + 或 C 实现会更快。

尽管如此,很多优化都可以在 C + + 中完成,这些优化会让你无法用 C # 完成任何事情,特别是在数字处理、实时和接近金属的领域,但不仅仅是这些领域。你甚至不需要触摸一个单指针就可以走很长的路。

所以根据你写的东西,我会选择其中一个。但是,如果您正在编写一些不依赖于硬件的东西(驱动程序、视频游戏等) ,我不会担心 C # 的性能(同样不能谈论 Java)。没问题的。

< < < < < < < < < < < < <

一般来说,某些笼统的论点在特定的帖子中听起来可能很酷,但是通常听起来并不一定可信。

无论如何,为了和平: AOT是伟大的,因为是 JIT。唯一正确的答案可能是: 视情况而定。真正聪明的人知道你可以同时利用两个世界的优势。

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.

这不合逻辑。使用中间表示并不会降低性能。例如,LLVM-GCC 通过 LLVM IR (这是一个虚拟的无限寄存器机器)将 C 和 C + + 编译成本机代码,并获得了出色的性能(通常优于 GCC)。

也许这更多的是一个编译器问题而不是语言问题,但是有人能够用简单的英语解释一下这些虚拟机器语言中的一种如何能够比本地语言表现得更好吗?

下面是一些例子:

  • 具有 JIT 编译的虚拟机有助于运行时代码的生成(例如 System.Reflection.Emit on。NET) ,所以你可以用 C # 和 F # 这样的语言动态编译生成的代码,但是必须用 C 或 C + + 编写一个相对较慢的解释器。例如,实现正则表达式。

  • Parts of the virtual machine (e.g. 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).

我也想解决一些问题,帕西巴尔的高度赞成的答案上面(因为有人不断删除我的意见对他的答案) ,提出了一个适得其反的两极分化的观点:

代码处理将在编译时完成..。

Hence template metaprogramming only works if the program is available at compile time which is often not the case, e.g. 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.

无论 JIT 优化如何,没有什么比直接指针访问内存更快的了... ... 如果你在内存中有连续的数据,通过 C + + 指针(例如 C 指针... ... 让我们给予凯撒应有的权限)访问它会比在 Java/C # 中快几倍。

人们之所以观察到 Java 在 SciMark2基准测试的 SOR 测试中击败了 C + + ,正是因为指针阻碍了与混叠相关的优化。

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.

我不认为性能需要考虑有关处理速度的服务器这些天(在所有的多核处理器进入市场)。它应该根据内存使用情况进行更多的定义。这样 Java 就有点不利了。
但是所有的编程语言都适合不同的用途。这就是他们的竞争领域,每个赛段都有不同的赢家。
And I am sure Java will win in the long run for it continues development and competitiveness it shows in all the new features it produce.
我在这里找到了一个 链接,它将支持我为 Java 投票的理由