C++ 性能与 Java/C#

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/145110/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-03 15:30:39  来源:igfitidea点击:

C++ performance vs. Java/C#

提问by user23126

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.

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

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?

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

采纳答案by Orion Adrian

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# 和 Java 可以一样快或更快,因为 JIT 编译器——一个在你的 IL 第一次执行时编译它的编译器——可以进行 C++ 编译的程序无法进行的优化,因为它可以查询机器。可以判断机器是Intel还是AMD;Pentium 4、Core Solo 或 Core Duo;或者是否支持 SSE4 等。

A C++ program has to be compiled beforehand usually with mixed optimizations so that it runs decently well on all machines, but is not optimized as much as it could be for a single configuration (i.e. processor, instruction set, other hardware).

C++ 程序必须预先编译,通常使用混合优化,以便它在所有机器上都能很好地运行,但没有像单个配置(即处理器、指令集、其他硬件)那样优化。

Additionally certain language features allow the compiler in C# and Java to make assumptions about your code that allows it to optimize certain parts away that just aren't safe for the C/C++ compiler to do. When you have access to pointers there's a lot of optimizations that just aren't safe.

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

Also Java and C# can do heap allocations more efficiently than C++ because the layer of abstraction between the garbage collector and your code allows it to do all of its heap compression at once (a fairly expensive operation).

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

Now I can't speak for Java on this next point, but I know that C# for example will actually remove methods and method calls when it knows the body of the method is empty. And it will use this kind of logic throughout your code.

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

So as you can see, there are lots of reasons why certain C# or Java implementations will be faster.

如您所见,某些 C# 或 Java 实现更快的原因有很多。

Now this all said, specific optimizations can be made in C++ that will blow away anything that you could do with C#, especially in the graphics realm and anytime you're close to the hardware. Pointers do wonders here.

现在这一切都说,可以在 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.

所以取决于你在写什么,我会选择其中一个。但是如果你写的东西不依赖于硬件(驱动程序、视频游戏等),我不会担心 C# 的性能(再次不能谈论 Java)。它会做得很好。

One the Java side, @Swatipoints out a good article:

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

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

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

回答by ine

It would only happen if the Java interpreter is producing machine code that is actually betteroptimized 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.

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

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.

然而,这种情况实际发生的几率非常低——除非 Java 有一个写得很好的库,而你有自己写得不好的 C++ 库。

回答by Peter Meyer

The executable code produced from a Java or C# compiler is not interpretted -- it is compiled to native code "just in time" (JIT). So, the first time code in a Java/C# program is encountered during execution, there is some overhead as the "runtime compiler" (aka JIT compiler) turns the byte code (Java) or IL code (C#) into native machine instructions. However, the next time that code is encountered while the application is still running, the native code is executed immediately. This explains how some Java/C# programs appear to be slow initially, but then perform better the longer they run. A good example is an ASP.Net web site. The very first time the web site is accessed, it may be a bit slower as the C# code is compiled to native code by the JIT compiler. Subsequent accesses result in a much faster web site -- server and client side caching aside.

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

回答by Giovanni Galbo

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).

除了其他人所说的,根据我的理解,.NET 和 Java 更擅长内存分配。例如,它们可以在内存碎片化时压缩内存,而 C++ 不能(本地,但如果您使用聪明的垃圾收集器,则可以)。

回答by paxdiablo

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#).

虚拟机语言不太可能胜过编译语言,但它们可以足够接近以至于无关紧要,因为(至少)以下原因(我在这里说的是 Java,因为我从未做过 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.

1/ Java 运行时环境通常能够检测频繁运行的代码段,并对这些部分执行即时 (JIT) 编译,以便将来它们以完全编译的速度运行。

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.

2/ Java 库的大部分是经过编译的,因此当您调用库函数时,您正在执行已编译的代码,而不是解释代码。您可以通过下载 OpenJDK 来查看代码(C 语言)。

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.

3/ 除非您进行大量计算,否则大部分时间您的程序都在运行,它在等待来自非常缓慢(相对而言)人类的输入。

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.

4/ 由于很多Java字节码的验证是在加载类的时候完成的,运行时检查的正常开销大大减少。

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.

5/ 在最坏的情况下,可以将性能密集型代码提取到编译模块并从 Java(参见 JNI)中调用,使其全速运行。

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 HUGEstandard library and the cross-platform nature.

总而言之,Java 字节码永远不会胜过本地机器语言,但有一些方法可以缓解这一点。Java 的一大优势(在我看来)是巨大的标准库和跨平台的特性。

回答by billjamesdev

I'm not sure how often you'll find that Java code will run faster than C++, even with Hotspot, but I'll take a swing at explaining how it could happen.

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

Think of compiled Java code as interpreted machine language for the JVM. When the Hotspot processor notices that certain pieces of the compiled code are going to be used many times, it performs an optimization on the machine code. Since hand-tuning Assembly is almost always faster than C++ compiled code, it's ok to figure that programmatically-tuned machine code isn't going to be toobad.

将编译后的 Java 代码视为 JVM 的解释型机器语言。当热点处理器注意到编译代码的某些部分将被多次使用时,它会对机器代码执行优化。由于手动调整 Assembly 几乎总是比 C++ 编译代码快,因此可以确定以编程方式调整的机器代码不会糟糕。

So, for highly repetitious code, I could see where it'd be possible for Hotspot JVM to run the Java faster than C++... until garbage collection comes into play. :)

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

回答by FlySwat

JIT (Just In Time Compiling) can be incredibly fast because it optimizes for the target platform.

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

This means that it can take advantage of any compiler trick your CPU can support, regardless of what CPU the developer wrote the code on.

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

The basic concept of the .NET JIT works like this (heavily simplified):

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

Calling a method for the first time:

第一次调用方法:

  • Your program code calls a method Foo()
  • The CLR looks at the type that implements Foo() and gets the metadata associated with it
  • From the metadata, the CLR knows what memory address the IL (Intermediate byte code) is stored in.
  • The CLR allocates a block of memory, and calls the JIT.
  • The JIT compiles the IL into native code, places it into the allocated memory, and then changes the function pointer in Foo()'s type metadata to point to this native code.
  • The native code is ran.
  • 您的程序代码调用方法 Foo()
  • CLR 查看实现 Foo() 的类型并获取与之关联的元数据
  • 从元数据中,CLR 知道 IL(中间字节码)存储在哪个内存地址中。
  • CLR 分配一块内存,并调用 JIT。
  • JIT 将 IL 编译为本机代码,将其放入分配的内存中,然后将 Foo() 的类型元数据中的函数指针更改为指向此本机代码。
  • 运行本机代码。

Calling a method for the second time:

第二次调用一个方法:

  • Your program code calls a method Foo()
  • The CLR looks at the type that implements Foo() and finds the function pointer in the metadata.
  • The native code at this memory location is ran.
  • 您的程序代码调用方法 Foo()
  • CLR 查看实现 Foo() 的类型并在元数据中找到函数指针。
  • 运行此内存位置的本机代码。

As you can see, the 2nd time around, its virtually the same process as C++, except with the advantage of real time optimizations.

如您所见,第二次,除了实时优化的优势外,它的过程几乎与 C++ 相同。

That said, there are still other overhead issues that slow down a managed language, but the JIT helps a lot.

也就是说,还有其他开销问题会降低托管语言的速度,但 JIT 有很大帮助。

回答by cero

In some cases, managed code can actually be fasterthan 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.

在某些情况下,托管代码实际上可能比本机代码更快。例如,“标记和清除”垃圾收集算法允许 JRE 或 CLR 等环境在一次传递中释放大量短期(通常)对象,其中大多数 C/C++ 堆对象被一次性释放一次。

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 tendsto be faster. How much faster? Well, it varies a whole lot, but it's not uncommon to see a 100% speed improvement. (2) In some cases, garbage collection can massivelyslow 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.

也就是说,我写了很多 C# 和很多 C++,我已经运行了很多基准测试。根据我的经验,C++ 在两个方面比 C# 快得多:(1) 如果您将一些用 C# 编写的代码移植到 C++,本机代码往往会更快。快多少?嗯,它变化很大,但看到 100% 的速度改进并不少见。(2) 在某些情况下,垃圾收集会大大降低托管应用程序的速度。.NET CLR 在处理大堆(例如,> 2GB)方面做得很糟糕,最终可能会在 GC 中花费大量时间——即使在具有很少——甚至没有——中间生命期对象的应用程序中也是如此。

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.

当然,在我遇到的大多数情况下,从长远来看,托管语言足够快,而且维护和编码权衡 C++ 的额外性能根本不是一个好方法。

回答by Joel Coehoorn

Generally, your program's algorithmwill be much more important to the speed of your application than the language. You can implement a poor algorithm in any language, including C++. With that in mind, you'll generally be able to write code the runs faster in a language that helps you implement a more efficient algorithm.

通常,程序的算法对应用程序的速度比语言重要得多。您可以使用任何语言(包括 C++)来实现糟糕的算法。考虑到这一点,您通常能够以一种有助于您实现更高效算法的语言编写运行速度更快的代码。

Higher-level languages do very well at this by providing easier access to many efficient pre-built data structures and encouraging practices that will help you avoid inefficient code. Of course, they can at times also make it easy to write a bunch of really slow code, too, so you still have to know your platform.

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

Also, C++ is catching up with "new" (note the quotes) features like the STL containers, auto pointers, etc -- see the boost library, for example. And you might occasionally find that the fastest way to accomplish some task requires a technique like pointer arithmetic that's forbidden in a higher-level language -- though they typcially allow you to call out to a library written in a language that can implement it as desired.

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

The main thing is to know the language you're using, it's associated API, what it can do, and what it's limitations are.

最重要的是要了解您正在使用的语言、相关的 API、它可以做什么以及它的限制是什么。

回答by Jay Bazuzi

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:

请记住,您的用户对您编写的软件速度的看法受到许多其他因素的影响,而不仅仅是代码生成器的优化程度。这里有些例子:

  • Manual memory management is hard to do correctly (no leaks), and even harder to do effeciently (free memory soon after you're done with it). Using a GC is, in general, more likely to produce a program that manages memory well. Are you willing to work very hard, and delay delivering your software, in an attempt to out-do the GC?

  • My C# is easier to read & understand than my C++. I also have more ways to convince myself that my C# code is working correctly. That means I can optimize my algorithms with less risk of introducing bugs (and users don't like software that crashes, even if it does it quickly!)

  • I can create my software faster in C# than in C++. That frees up time to work on performance, and still deliver my software on time.

  • It's easier to write good UI in C# than C++, so I'm more likely to be able to push work to the background while UI stays responsive, or to provide progress or hearbeat UI when the program has to block for a while. This doesn't make anything faster, but it makes users happier about waiting.

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

  • 我的 C# 比我的 C++ 更容易阅读和理解。我还有更多方法让自己相信我的 C# 代码可以正常工作。这意味着我可以优化我的算法,降低引入错误的风险(并且用户不喜欢崩溃的软件,即使它会很快崩溃!)

  • 我可以用 C# 比用 C++ 更快地创建我的软件。这样可以腾出时间来处理性能问题,同时仍能按时交付我的软件。

  • 用 C# 编写好的 UI 比用 C++ 更容易,所以我更有可能在 UI 保持响应的同时将工作推送到后台,或者在程序必须阻塞一段时间时提供进度或收听 UI。这不会使任何事情变得更快,但它使用户对等待感到高兴。

Everything I said about C# is probably true for Java, I just don't have the experience to say for sure.

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