Java 集合比 c++ 容器更快?

我正在阅读有关此答案的评论,我看到了这句话。

对象实例化和面向对象的功能使用起来非常快(在许多情况下比C++快),因为它们是从一开始就设计的。和集合速度很快。标准Java在这方面优于标准C / C++,即使对于大多数优化的C代码也是如此。

一位用户(我可能会补充一下,代表率非常高)大胆地捍卫了这一说法,并指出

  1. java中的堆分配比C++的更好

  2. 并添加了此语句,以java保护集合

    与C++集合相比,Java集合的速度很快,这主要是由于不同的内存子系统。

所以我的问题是,这些真的可以吗,如果是这样,为什么java的堆分配要快得多。


答案 1

这种说法是荒谬的。制作它的人要么非常不知情,要么非常不诚实。特别:

  • 在这两种情况下,动态内存分配的速度将取决于动态内存使用的模式以及实现。对于熟悉这两种情况中使用的算法的人来说,编写一个基准测试来证明他想更快地是微不足道的。(因此,例如,使用大型复杂图形的程序,这些图形被构建,然后被拆除和重建,通常在垃圾回收下运行得更快。从不使用足够的动态内存来触发收集器的程序也是如此。使用少量、大型、长期分配的程序通常可以通过手动内存管理更快地运行。

  • 比较集合时,必须考虑集合中的内容。例如,如果您正在比较 的大向量,Java 和 C++之间的差异可能很小,并且可能会向任何方向发展。如果你正在比较的大向量,其中是一个包含两个双精度值的值类,C++可能会把Java从水中吹出来,因为它使用纯值语义(没有额外的动态分配),而Java需要动态分配每个(并且没有动态分配总是比最快的动态分配更快)。如果 Java 中的类被正确地设计为充当值(因此是不可变的,如 ),那么在向量中执行转换将需要为每个 ;在C++,您可以分配。doublePointPointPointPointjava.lang.StringPointPoint

  • 很大程度上取决于优化器。在Java中,优化器在程序的特定运行中完全了解实际用例,并在此运行中完全了解它正在运行的实际处理器。在C++,优化程序必须使用分析运行中的数据,这些数据永远不会与程序的任何一次运行完全对应,并且优化程序必须(通常)生成将在各种处理器版本上运行(并快速运行)的代码。另一方面,C++优化器可能需要花费更多的时间来分析不同的路径(有效的优化可能需要大量的CPU);Java优化器必须相当快。

  • 最后,尽管并非所有应用程序都相关,但C++可以是单线程的。在这种情况下,分配器中不需要锁定,这在Java中从来都不是这种情况。

关于两个编号点:C++可以在其堆分配器中使用或多或少与Java相同的算法。我使用过C++程序,其中函数为空,内存被垃圾回收。(如果您的应用程序分配了大量短期的小对象,则这样的分配器可能会加快速度。至于第二个:C++拥有的真正大的优势是,它的内存模型不需要动态分配所有内容。即使Java中的分配只花费了C++所花费时间的十分之一(如果您只计算分配,而不是收集器扫描所需的时间,情况可能就是这样),如上所述,使用大型向量,您将C++中的两到三个分配与Java中的数百万个分配进行比较。::operator delete()Point

最后:“为什么Java的堆分配速度要快得多?如果您摊销收集阶段的时间,则不一定如此。分配本身的时间可能非常便宜,因为Java(或至少大多数Java实现)使用重定位收集器,这导致所有可用内存都在单个连续块中。这至少部分被收集器中所需的时间所抵消:要获得这种连续性,您必须移动数据,这意味着需要大量复制。在大多数实现中,它还意味着指针中的附加间接寻址,以及许多特殊逻辑,以避免当一个线程在寄存器中具有地址时出现问题,等等。


答案 2

你的问题没有具体的答案。例如,C++根本不定义内存管理。它将分配详细信息留给库实现。因此,在C++的范围内,给定的平台可能具有非常慢的堆分配方案,如果绕过它,Java肯定会更快。在另一个平台上,内存分配可能非常快,性能优于Java。正如James Kanze所指出的,Java对内存管理的限制也很少(例如,甚至GC算法也完全取决于JVM实现器)。因为 Java 和 C++ 没有对内存管理施加约束,所以这个问题没有具体的答案。C++对底层硬件和内核功能是有意开放的,而Java是关于JVM内存管理的有意开放。所以这个问题变得非常模糊。

您可能会发现,在 Java 中,有些操作更快,而有些则不然。然而,在你尝试之前,你永远不会知道

在实践中,真正的区别在于您的更高级别算法和实现。除了性能最关键的应用程序之外,对于所有绝对性能关键的应用程序,与算法本身的性能特征相比,不同语言中相同数据结构的性能差异完全可以忽略不计。专注于优化更高级别的实现。只有在您这样做之后,并且在确定您的性能要求没有得到满足之后,并且在您进行了基准测试并发现(不太可能)您的瓶颈在容器实现中之后,您才应该开始考虑这样的事情。

一般来说,一旦你发现自己在思考或阅读C++与Java问题,就停下来,重新专注于一些富有成效的事情。


推荐