现代Java是最快的语言之一,即使它仍然是一个内存猪。 Java有缓慢的声誉,因为它以前需要很长时间为VM启动。
如果你仍然认为Java很慢,请参见the benchmarks game结果。用先行编译语言(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多LOT内存,如果你的应用程序是内存绑定或内存带宽绑定(缓存等),这使它更慢。另一方面是分配/释放是快速的(高度优化)。这是现在大多数高级语言的一个特性,并且由于对象和使用GC而不是显式内存分配。加上坏图书馆的决定。
>基于流的I / O缓慢,由于(IMO,差的选择)要求在每个流访问上的同步。 NIO固定这个,但是使用起来很痛。可以通过读取/写入数组,而不是一次一个元素来解决这个问题。
> Java不提供同样的低级功能C,所以你不能使用脏内联汇编技巧,使一些操作更快。这提供了可移植性,并且是大多数高级语言的一个特性。
>通常将Java应用程序绑定到非常旧的JVM版本。特别是服务器端。与最新版本相比,这些旧的JVM可能难以置信的低效率。
最终,Java被设计为以牺牲一些性能为代价提供安全性和可移植性,并且对于一些真正要求苛刻的操作,它显示出来。它的大部分的缓慢的声誉不再是应得的。
但是,有几个地方的Java比大多数其他语言更快:
>内存分配和取消分配
是快速和便宜。我见过的情况
在那里它是20%更快(或更多!)到
分配一个新的,多kB的数组
重用缓存的一个。
>对象实例化和面向对象的特性使用起来很快(在某些情况下比C快),因为它们是从头开始设计的。这部分来自良好的GC,而不是显式分配(这对于许多小对象分配更友好)。一个可以编码C打败这(通过滚动定制内存管理和有效地执行malloc),但这不容易。
>方法调用基本上是免费的,在某些情况下比大方法代码更快。 HotSpot编译器使用执行信息来优化方法调用,并具有非常高效的内联。通过使用附加的执行信息,它有时可以胜过提前编译器,甚至(在极少情况下)手动内联。与C/C++比较,如果编译器决定不内联,方法调用具有小的性能损失。
>同步和多线程是容易和高效的。 Java被设计为从一开始就是线程感知的,它显示。现代计算机通常具有多个内核,并且由于线程是内置的语言,你可以很容易地利用。基本上,额外的100%到300%的速度提升与标准的单线程C代码。是的,仔细编写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从来没有在桌面上。
>大量使用库类中的同步;非同步版本现在可用
> Applet永远加载,因为通过网络传输一个完整的JAR和加载VM启动。>同步用于承担严重的性能损失(这已经针对每个Java版本进行了优化)。反思仍然是昂贵的。