Java真的很慢吗?

Ste*_*ini 180 java performance

Java 在缓慢方面有一定程度的声誉.

  • Java真的很慢吗?
  • 如果是,为什么?瓶颈在哪里(或曾经)?是因为效率低下的JVM?垃圾收集?纯字节码库而不是JNI包装的C代码?许多其他语言都具有这些功能,但它们并不具有这种缓慢的声誉.

Bob*_*Gee 236

现代Java是最快的语言之一,尽管它仍然是一种记忆力.Java的用于速度缓慢,因为它曾经花费很长的时间VM启动的声誉.

如果您仍然认为Java很慢,请参阅基准测试游戏结果.用提前编译语言(C,Fortran等)编写的紧密优化代码可以击败它; 但是,Java的速度可以是PHP,Ruby,Python等的10倍.在特定领域,它可以胜过常见的编译语言(如果它们使用标准库).

现在没有"慢"Java应用程序的借口.开发人员和遗留代码/库应该归咎于远远超过语言.还有,责怪任何"企业".

为了公平对待"Java慢"的人群,这里仍然很慢(2013年更新):

  • 库通常是为"正确性"和可读性而非性能而编写的.在我看来,这是Java仍然声名狼借的主要原因,尤其是服务器端.这使得String问题呈指数级恶化.一些简单的错误很常见:通常使用对象代替基元,从而降低性能并增加内存使用.许多Java库(包括标准库)将经常创建字符串,而不是重用可变或更简单的格式(char []或StringBuffer).这很慢并且会产生大量的垃圾以便以后收集.为了解决这个问题,我建议开发人员尽可能使用原始集合,尤其是Javalution的库.

  • 字符串操作有点慢.Java使用不可变的,UTF-16编码的字符串对象.这意味着您需要更多内存,更多内存访问,而某些操作比使用ASCII(C,C++)更复杂.当时,这是可移植性的正确决定,但它的性能成本很低.UTF-8现在看起来是更好的选择.

  • 由于边界检查,与C相比,数组访问速度稍慢.过去的惩罚很大,但现在很小(Java 7优化了很多冗余边界检查).

  • 缺乏任意内存访问可能会使某些I/O和位级处理变慢(例如压缩/解压缩).这是现在大多数高级语言的安全功能.

  • Java使用的内存比C多,如果您的应用程序受内存限制或内存带宽限制(缓存等),则会使速度变慢.另一方面,分配/解除分配的速度非常快(高度优化).这是现在大多数高级语言的一个特性,并且由于对象和GC的使用而不是显式内存分配. 加上坏的图书馆决定.

  • 由于(IMO,选择不当)要求在每个流访问上进行同步,基于流的I/O很慢.NIO解决了这个问题,但使用它很痛苦.通过对数组进行读/写操作,而不是一次一个元素,可以解决这个问题.

  • Java没有提供与C相同的低级功能,因此您不能使用脏内联汇编程序技巧来加快某些操作.这提供了可移植性,现在是大多数高级语言的一个特性.

  • 通常看到Java应用程序与非常旧的JVM版本相关联.特别是服务器端.与最新版本相比,这些旧JVM的效率极低.

最后,Java旨在以牺牲一些性能为代价来提供安全性和可移植性,以及它所展示的一些非常苛刻的操作.它的缓慢声誉大部分都不再值得.


但是,有几个地方Java 比大多数其他语言更快:

  • 内存分配和解除分配快速且便宜.我已经看到分配一个新的多KB阵列比重用缓存的数据快20%(或更多!)的情况.

  • 对象实例化和面向对象的特性使用起来非常快(在某些情况下比C++更快),因为它们从一开始就被设计出来.这部分来自良好的GC而不是显式分配(对许多小对象分配更友好).人们可以编写C代码(通过滚动自定义内存管理并高效地执行malloc),但这并不容易.

  • 方法调用基本上是免费的,在某些情况下比大方法代码更快.热点编译器使用的执行信息来优化方法调用,具有非常高效的内联.通过使用额外的执行信息,它有时可以胜过提前编译器甚至(在极少数情况下)手动内联.与C/C++相比,如果编译器决定不内联,方法调用会带来很小的性能损失.

  • 同步和多线程简单而有效.Java从一开始就被设计为线程感知,并且它表明了.现代计算机通常具有多个内核,并且由于线程内置于该语言中,因此您可以非常轻松地利用它.与标准的单线程C代码相比,基本上可以提供100%到300%的额外速度提升.是的,精心编写的C线程和库可以击败这个,但这对程序员来说是一项额外的工作.

  • 字符串包括长度:某些操作更快.这使用空分隔字符串(在C中很常见).在Java 7中,Oracle取消了String.subString()优化,因为人们愚蠢地使用它并且导致内存泄漏.

  • 阵列副本经过高度优化.在最新版本中,Java使用手动调整的汇编程序进行System.arraycopy.结果是在arraycopy/memcopy-heavy操作中,我看到我的代码在C中以合理的余量击败了等价物.

  • JIT编译器很聪明地使用L1/L2缓存.提前编译的程序无法实时地将其代码调整到它们运行的​​特定CPU和系统.JIT以这种方式提供了一些非常有效的循环转换.

其他一些历史事实促成了"Java缓慢"的声誉:

  • 在JIT编译之前(Java 1.2/1.3),语言只是被解释,而不是编译,因此非常慢.
  • JIT编译需要时间才能变得高效(每个版本都有重大改进)
  • 多年来,类加载已经变得更加高效.它曾经是非常低效和启动过程中的慢.
  • Swing和UI代码没有很好地使用本机图形硬件.
  • 摇摆很糟糕.我责怪AWT和Swing为什么Java从未在桌面上流行起来.
  • 在库类中大量使用同步; 现在可以使用非同步版本
  • 小程序需要永远加载,因为通过网络传输完整的JAR并加载VM以进行引导.
  • 同步过去会带来严重的性能损失(这已针对每个Java版本进行了优化).但是,反思仍然很昂贵.

  • `对象实例化和面向对象的特性使用起来非常快(在许多情况下比C++更快),因为它们从一开始就被设计出来.并且`集合很快.标准Java在该领域击败标准C/C++,即使对于大多数优化的C代码也是如此.这里提供的任何证据都不支持疯狂的声明. (49认同)
  • @Rex Kerr - 基本上你声称这是因为Java中的所有内容都涉及在堆上分配内存,并且因为Java在Java上的堆上分配比C++快,所以Java中的所有内容都更快.这里有一些消息:在C++中,你可以在很多情况下不在堆上分配内存! (20认同)
  • @Rex Kerr - 如果你可以使用例如堆栈进行分配,为什么要使用内存处理程序?!您将堆内存分配与对象实例化混淆. (15认同)
  • @Sjoerd - 我在哪里说Java中的_everything_更快?刚看完我说的话.我说了我的意思,并且已经解决了你在上次评论中所说的一切. (10认同)
  • @Sjoerd - 这些说法几乎不是很疯狂 - 对我来说很明显,对于那些理解C/C++与Java中默认内存系统架构差异的人来说应该是这样.如果您编写自己的内存处理程序(使用自由列表,内存池等等)或使用实现此类内容的库,那么您可以做得更好. (8认同)
  • 阵列副本经过高度优化.在最新的1.6.x版本中,Java使用手动调整的汇编程序进行System.arraycopy - 这意味着java使用了C/C++版本的arraycopy ...顺便说一下它就像一个C或C++版本一样快,而不是快点.这就像Javascript V8正则表达式引擎,当它使用C lib来使正则表达式成为可能时,可能会击败C - 这只是一个C实现击败另一个. (5认同)
  • @BobMcGee计算机,而不是Java,变得更快.为什么不将这些数据与Python的Django,Ruby on Rails,Node.js以及所有其他数据进行比较?如果要包含编译步骤的语言,您甚至可以与Go进行比较.在现代硬件上启动两秒钟是一个非常漫长的时间.对于任何不称为"Java"的东西,甚至不可能想到15秒. (3认同)
  • @Rex Kerr - 原始的Java集合类必须重新设计,因为使它们成为线程安全的决策结果证明是一个性能问题.与旧的相比,新的集合类闪电般快,但我看不出它们为什么比它们的C++计数器部分更快的原因. (2认同)
  • 向我展示一个严肃而复杂的Java GUI应用程序,它并不完全贬低性能.例如,Azureus完全糟糕的性能.它是我真正容忍的唯一严肃的Java应用程序,因为它功能强大,没有太多错误,并且运行良好,我可以忍受恶劣的性能. (2认同)
  • 几个注意事项:您可以使用sun.misc.Unsafe进行任意内存访问,在64位JVM中,Java默认使用32位引用,而64位C应用程序默认使用64位引用和大小.这可能意味着C使用更多内存.如果更紧凑是必不可少的,你可以编写自己的ByteString类.我编写了一个库,它通过内存映射文件支持延迟为100 ns或更短的进程之间的持久消息传递.这通常足够快. (2认同)
  • 等待VM启动**使用**慢?你在跟我开玩笑吗?只需比较重启Tomcat以重新启动使用任何其他动态语言编写的任何其他应用程序服务器.我的意思是**其他任何**.让我们不要开始使用内存. (2认同)
  • @Tobia问题是问题是Java本身还是Java应用服务器生态系统.世界上超过一半的智能手机运行Java(Android)应用程序,并且没有看到很多关于启动时间的抱怨.我认为问题在于编写应用程序服务器的方式. (2认同)
  • ARM的ThumbEE(Jazelle RCT)具有硬件阵列边界检查指令,这对移动设备来说是一个很好的推动.此外,要添加到Java加号列表中的内容是基于当前体系结构和实际运行时特征的JIT编译. (2认同)

nos*_*nos 49

最初Java并不是特别快,但它也不是太慢.这些天,Java非常快.从与人交谈过的人们对Java缓慢的印象来自两件事:

  1. 虚拟机启动时间较慢.与本机应用程序相比,早期的Java实现需要很长时间才能启动并加载require库和应用程序.

  2. 慢UI.早期的挥杆很慢.它可能没有帮助大多数Windows用户发现默认的金属L&F丑陋.

鉴于以上几点,难怪人们得到了"Java缓慢"的印象.

对于用于开发本机应用程序甚至Visual Basic应用程序的用户或开发人员来说,这两点是应用程序中最明显的一点,它是您对应用程序的第一印象(除非它是一个非GUI应用程序,其中情况只有1.适用.).

当应用程序需要8秒钟启动时,你不会说服用户"它执行代码的速度非常快"与他立即启动的旧Visual Basic应用程序 - 即使代码执行和启动时间可能根本没有连接.

破坏第一印象是开始谣言和神话的好方法.谣言和神话很难被杀死.

简而言之,Java并不慢.拥有"Java态度缓慢"的人是基于10多年前对Java的第一印象.

  • Macbook上的OSX 10.6上的Java应用程序启动速度比使用Objective-C编写的应用程序慢得多.快速启动时间的证据是什么? (23认同)
  • @Zan:请注意,Mac OS X的JVM是由Apple编写的(或至少是适应过的).Sun已投入相当长的时间在其支持的平台(Windows,Linux和Solaris)上使启动时间更快,但他们无法在Mac OS x上执行此操作(因为他们不维护该端口).可能是Mac无法/不会将所有这些优化应用/移植到Mac OS X. (5认同)
  • Java在几年前非常慢,但在最近的基准测试中,它的运行速度几乎和C/C++一样快,在某些情况下运行得更快. (3认同)
  • 减压绝对不是性能问题.1992年,我的计算机在启动程序时解压缩了可执行程序,这些程序提高了从硬盘加载较长文件的性能.在这几年中,CPU和硬盘之间的差距已经大大增加.但是,使用zip存档格式rt.jar(为什么?!!!)存在问题,并且所包含的类文件没有链接(坚果!!). (2认同)

Sam*_*ami 40

在阅读了一篇充满评论的页面后,说Java并不慢,我只需回答一个不同的意见.

语言的缓慢很大程度上取决于你对"快速"的期望.如果你认为C#很快,Java肯定也很快.如果您的问题域与数据库或半实时处理相关,那么Java肯定也足够快.如果您乐意通过添加更多硬件来扩展应用程序,那么Java可能很快.如果你认为5-10级的常数因子加速并不值得,你可能会认为Java很快.

如果对大型数据集进行数值计算,或者绑定到CPU资源有限的执行环境,那么5-10级的恒定加速将是巨大的.即使0.5加速也可能意味着计算完成时减少500小时.在这些情况下,Java只是不允许你获得最后一码的性能,并且你可能认为Java很慢.

  • 同意,并且在整个帖子上+1,因为你提出了一个有效的观点,但是,例如C++有着不同的名称,难以调试,并且很容易让你的整个腿断开,但我很少听说C++的速度很慢我听说过java. (2认同)

Jer*_*fin 33

你似乎在问两个相当不同的问题:

  1. Java真的很慢,如果是这样,为什么呢?
  2. 为什么Java被认为是缓慢的,尽管它比许多替代品更快?

其中第一个或多或少是"绳索有多长"的问题.它归结为你对"慢"的定义.与纯解释器相比,Java速度极快.与(通常)编译为某种字节码的其他语言相比,然后动态编译为机器代码(例如C#或.NET上的任何其他内容),Java大致相当.与通常编译为纯机器代码的语言相比,并且(通常很大的)团队除了改进他们的优化器(例如C,C++,Fortran,Ada)之外什么也没有做任何事情时,Java在一些事情上做得很好,但整体而言往往至少有点慢.

其中很多主要与实现有关 - 基本上,它归结为用户在动态/ JIT编译器运行时等待的事实,所以除非你有一个程序运行了很长一段时间才开始,所以难以证明编译器花费大量时间进行困难的优化.因此,大多数Java(和C#等)编译器都没有花费太多精力进行真正困难的优化.在很多情况下,与实施优化相比,优化程度更低.许多优化问题都是NP完成的,因此随着问题被攻击的大小,它们所花费的时间会迅速增长.将时间保持在合理范围内的一种方法是一次仅将优化应用于单个函数.当只有开发人员等待编译器时,您可以花费更长的时间,并将相同的优化应用于程序的更大块.同样,一些优化的代码非常多(因此可能非常大).同样,由于用户正在等待该代码加载(并且JVM启动时间通常是整个时间中的一个重要因素),实现必须平衡在一个地方保存的时间与在另一个地方丢失的时间 - 并且给出了很少的代码从毛茸茸的优化中获益,保持JVM较小通常更有益.

第二个问题是,使用Java,您经常会获得或多或少的"一刀切"解决方案.例如,对于许多Java开发人员来说,Swing本质上是唯一可用的窗口库.在像C++这样的东西中,实际上有几十个窗口库,应用程序框架等,每个窗口都有自己的易用性和快速执行之间的妥协,一致的外观和原生的外观和感觉等等.唯一真正的关键点是一些(例如Qt)可能非常昂贵(至少对于商业用途而言).

第三,用C++编写的许多代码(以及C更加如此)只是更老,更成熟.很多时候,它包含了几十年前编写的一系列例程,当时花费额外的时间优化代码是正常的预期行为.这通常会在代码更小更快的情况下获得真正的好处.C++(或C)获得了代码小而快的功能,但它实际上是开发人员的产品和代码编写时间的约束.在某种程度上,这导致了一种自我实现的预言 - 当人们关心速度时,他们经常选择C++,因为它具有这种声誉.他们将额外的时间和精力投入到优化中,并编写了新一代的快速C++代码.

总而言之,Java的正常实现使得最大化优化最多成为问题.更糟糕的是,在Java 可见的地方,诸如窗口工具包和JVM启动时间之类的东西通常比语言本身的执行速度发挥更大的作用.在很多情况下,C和C++也因为简单地在优化中更加努力的产品而受到赞誉.

至于第二个问题,我认为这在很大程度上取决于工作中的人性问题.一些狂热者提出了相当夸张的关于Java快速致命的说法.有人试了一下,发现即使是一个微不足道的程序也需要几秒钟的时间才能开始,并且当它运行时感觉缓慢且笨拙.很少有人可能会费心去分析事情,因为很多事情都是JVM的启动时间,以及当他们第一次尝试时,没有编译代码的事实 - 一些代码正在被解释,还有一些是在他们等待时编译的.更糟糕的是,即使它运行得足够快,对于大多数用户来说,外观和感觉通常看起来也很笨拙,所以即使客观测量显示出快速的响应时间,它仍然看起来很笨拙.

将这些添加在一起会导致相当简单和自然的反应:Java是缓慢,丑陋和笨拙的.鉴于大肆宣传它真的很快,有一种倾向过度反应和结论认为它非常缓慢,而不是(更准确)"稍微慢一点,而且主要是在特定情况下." 对于使用该语言编写前几个程序的开发人员来说,这通常是最糟糕的.在大多数语言中执行"hello world"程序会立即出现,但在Java中,JVM启动时会有一个容易察觉的暂停.即使是在紧密循环上运行速度慢得多的纯解释器,对于像这样的代码来说仍然会更快出现,只是因为它可以加载并开始执行一点点.


Dan*_*yer 16

它是早期(20世纪90年代中后期)Java的过时信息.与之前的版本相比,Java的每个主要版本都引入了显着的加速.由于Oracle显然将JRockit与Sun的JVM for Java 7合并,这种趋势似乎将继续下去.

与许多其他流行的现代语言(Python,Ruby,PHP)相比,Java在大多数用途中实际上要快得多.它与C或C++不完全匹配,但对于许多任务而言,它足够接近.真正的性能问题应该是它最终使用多少内存.


Tho*_*nin 14

"长启动时间"的主要罪魁祸首是动态链接.Java应用程序由已编译的类组成.每个类按名称引用其他类(对于参数类型,方法调用...).JVM必须在启动时检查并匹配这些名称.它会逐步增加,只在任何给定时间执行它所需的部分,但这仍然是一些工作要做.

在C应用程序中,链接阶段发生在编译结束时.它很慢,特别是对于大型应用程序,但只有开发人员才能看到它.链接产生一个可执行文件,操作系统只需要"按原样"加载到RAM中.

在Java中,每次运行应用程序时都会发生链接.因此启动时间很长.

已经应用了各种优化,包括缓存技术,并且计算机变得更快(并且它们比应用程序"更大"更"快"),因此最近问题的重要性大大降低; 但旧的偏见仍然存在.

至于之后的性能,我自己的基于数组访问的紧凑计算基准(主要是散列函数和其他加密算法)通常表明优化的C代码比Java代码快3倍左右; 有时C只比Java快30%,有时C可以快4倍,具体取决于实现的算法.当"C"代码实际上是大整数算术的汇编时,我看到了一个10倍因子,因为处理器提供的64x64-> 128乘法操作码但Java无法使用,因为它的最长整数类型是64位long.这是一个边缘案例.在实际条件下,I/O和内存带宽考虑因素阻止C代码实际上比Java快三倍.

  • @Sean:C的动态链接出现在"外部符号"中:在一个DLL中使用并在另一个DLL中定义的函数.典型的C应用程序将使用十几个DLL.对于Java,所有类中的所有方法都会发生动态链接:典型Java应用程序(包括标准库)中有___千个.在C世界中,大多数链接(所有不跨越DLL边界的链接)在编译时被解析,在运行时仍然只有一小部分要做. (4认同)

小智 14

Java肯定很慢,特别是对于量化工作.

我将R,Python和C/C++与优化的多线程ATLAS库结合使用.在每种语言中,我可以在大约4秒内将矩阵乘以3000乘3000矩阵.在Java中使用Colt和Parallel Colt,相同的操作需要185秒!尽管这些java库本质上是并行的,但令人惊讶.

总而言之,纯Java不适合定量工作.Jblas似乎是Java中最好的线性代数库,因为它使用ATLAS.

我的机器是带有3 GB RAM 的HP Core 2 Duo.我使用的是64位Ubuntu 10.04(Lucid Lynx).

  • 在通过JNI调用的库中执行乘法时,Java需要多长时间.考虑到你可以用C/C++做的任何东西,你可以用JNI(加上几百毫秒),边距相对较小.我猜你的R和Python矩阵乘法不是用R或Python编写的,只是从那些语言调用. (7认同)
  • 出于好奇,你有没有进行任何分析,以确定你的代码中是否有一些热点(类型转换/自动装箱)? (2认同)

Spi*_*ams 10

对于大多数人与它交互的经验 - Java 慢.在一些小程序出现之前,我们都看到咖啡杯在我们的浏览器上旋转.启动JVM并下载applet二进制文件需要一段时间,这会以一种被注意到的方式影响用户体验.

缓慢的JVM启动和applet下载时间明显标有Java咖啡杯,这无助于人们将等待与Java联系在一起.当Flash需要很长时间加载时,Flash加载程序会指定"加载"消息的标记,因此人们不会将Flash技术归咎于整体.

所有这些都与Java在服务器上的性能无关,也与Java在浏览器外部使用的许多其他方式无关.但这是人们看到的内容,以及非Java开发人员在考虑Java时所记得的内容.


Rex*_*err 9

Java有被缓慢的,因为它的名声缓慢的.Java的第一个版本没有或相当差的Just In Time编译.这意味着代码(尽管字节码)正在被解释,因此即使对于最简单的操作(如添加两个整数),机器也必须进行各种比较和指针解引用和函数调用.JIT编译器一直在不断改进; 现在,如果我不小心编写C++代码和粗略地编写Java代码,Java有时会胜过 C++,因为JIT编译器意识到我有一些不必要的指针解除引用并将为我处理它.

如果您想了解JIT编译的差异有多大,请查看计算机语言基准游戏中的解释与非解释基准.(Pidigits使用外部库进行所有计算,因此基准测试不会改变;其他计算机显示6-16倍的加速!)

所以,这是主要原因.还有其他一些不太重要的原因没有帮助:最初,Java启动时间很慢(现在已经修复); Java中的Web应用程序需要花费很长时间才能下载(现在宽带可以广泛使用,并且需要大量电影等); UI Swing不是(现在仍然没有)以性能为基础编写的,所以它比C++中的等价物要简单得多.


Kal*_*see 6

Java在日复一日缓慢.由于几代性能增强,它变得更快.最后我听说,它通常在C#速度的10%以内 - 有时更快,有时更慢.

Java applet启动仍然很慢,因为你必须启动一个完整的JVM,它必须加载它的所有类.有点像启动另一台电脑.一旦JVM启动它很快,但启动通常是人们记住的.

此外,至少有一些人永远不会相信Java的可行性.

  • 哇,Java 6是4岁??? 是的,我想是的(如果算上测试版).对我来说仍然感觉很新 - 我刚刚在工作中停止使用1.4. (3认同)

Die*_*ter 6

斯特凡诺:

我从一开始就使用Java,所以从我的观点来看,缓慢的名声是由非响应和慢的GUI前端(AWT,然后是Swing)和Applet创建的,可能是因为它的启动时间较慢. VM的.

Java在VM领域已经规定并推动了大量的研究,并且已经有了相当多的改进,包括垃圾收集(你可以实际调整很多东西;但是,我常常看到只使用默认值的系统)和热点优化(在开始时,可​​能仍然在服务器端更有效).

后端的Java和计算级别并不那么慢.柯尔特是最好的例子之一:

最新稳定的Colt版本打破了JDK ibm-1.4.1,RedHat 9.0,2x IntelXeon@2.8 GHz的1.9 Gflop/s障碍.

应该考虑主流Java之外的许多东西,比如Realtime Java或增强速度的特殊机制,如Javolution,以及Ahead-Of-Time编译(如gcj).此外,还有可以直接执行Java Bytecode的IC,例如当前iPhone和iPod ARM Jazelle中的那个.

我认为通常今天它是一个政治决定(就像iPhone/iPod上没有Java支持一样),并且决定将Java作为一种语言(因为许多人认为它太冗长).

但是,现在Java VM还有许多其他语言(例如Python,Ruby,JavaScript,Groovy,Scala等),它们可能是另一种选择.

我个人继续喜欢它作为一个灵活可靠的平台,具有出色的工具和库可用性,允许人们使用从最小的设备(例如JavaCard)到最大的服务器的所有东西.