Java真的很慢吗?

Java有一定的缓慢的声誉 。

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

现代Java是最快的语言之一,即使它仍然是一个内存猪。 Java 一个缓慢的声誉,因为它启动需要很长时间。

如果您仍然认为Java很慢 ,请参阅基准游戏结果。 用提前编译的语言(C,Fortran等)编写的紧密优化的代码可以胜过它; 然而,Java的速度可能比PHP,Ruby,Python等快10倍以上。有一些特定领域可以击败公共编译语言(如果他们使用标准库)。

现在没有理由“慢”的Java应用程序。 开发人员和遗留代码/库的责任,远远超过语言。 另外,还要怪任何“企业”。

公平的说,“Java是慢”的人群,这里仍然是缓慢的地区(2013年更新):

  • 图书馆往往是为了“正确”和可读性而不是performance。 在我看来,这是Java仍然声誉不佳的主要原因,特别是服务器端。 这使得string问题成倍地恶化。 一些简单的错误是常见的:对象经常用来代替原语,降低性能和增加内存使用。 许多Java库(包括标准库)会频繁地创buildStrings,而不是重复使用可变或更简单的格式(char []或者StringBuffer)。 这很慢,并创build大量的垃圾收集后。 为了解决这个问题,我build议开发者尽可能使用原始的集合,特别是Javalution的库。

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

  • 由于边界检查,数组访问比C慢一些 。 过去的惩罚很大,但现在很小(Java 7优化了大量的冗余边界检查)。

  • 没有任意的内存访问可以使一些I / O和位级处理变慢(例如压缩/解压缩)。 这是现在大多数高级语言的安全function。

  • Java使用比C多的内存,如果你的应用程序是内存绑定或内存带宽绑定(caching等),这使得它变慢。 另一方面是分配/释放快速(高度优化)。 这是现在大多数高级语言的一个特性,由于对象和GC的使用而不是显式的内存分配。 加上不好的图书馆决定

  • 基于stream的I / O速度很慢,因为(IMO,糟糕的select)要求每个stream访问同步。 NIO解决了这个问题,但是使用起来很麻烦 。 人们可以通过读取/写入数组而不是一次一个元素来解决这个问题。

  • Java不提供与C一样的低级function,所以你不能使用脏的内联汇编技巧来加快一些操作。 这提供了可移植性,是现在大多数高级语言的一个特性。

  • 将Java应用程序绑定到非常旧的JVM版本是很常见的。 特别是服务器端。 与最新版本相比,这些旧的JVM可能效率非常低。

最终,Java被devise为提供安全性和可移植性,而牺牲一些性能,以及对于一些非常苛刻的操作。 它的缓慢声誉大部分已经不值得。


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

  • 内存分配和取消分配是快速和便宜的。 我已经看到了分配一个新的多kB数组比快速重复(或更多)的情况,而不是重用caching的情况。

  • 对象实例化和面向对象的特性正在快速地使用 (在某些情况下比C ++更快),因为它们是从一开始就devise的。 这部分来自良好的GC而不是明确的分配(对许多小对象分配来说这更友好)。 我们可以编写C代码(通过滚动自定义内存pipe理和高效地执行malloc),但这并不容易。

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

  • 同步和multithreading是简单而高效的。 Java被devise成从一开始就是线程感知的,并且显示出来。 现代计算机通常具有多个内核,因为线程内置于语言中,所以您可以非常轻松地利用。 与标准的单线程C代码相比,基本上可以提高100%到300%的速度提升。 是的,仔细写的C线程和库可以打败这个,但是这是程序员额外的工作。

  • string包括长度:一些操作更快。 这使用空分隔的string(在C中常见)。 在Java 7中,Oracle取出了String.subString()优化,因为人们在愚蠢地使用它,导致内存泄漏。

  • arrays副本高度优化。 在最新版本中,Java使用System.arraycopy的手动调整汇编器。 结果是,在arraycopy / memcopy-heavy操作中,我看到我的代码以合理的边距击败了C中的等价物。

  • JIT编译器在使用L1 / L2caching方面非常聪明 。 提前编译的程序不能实时调整代码到特定的CPU和系统上运行。 JIT以这种方式提供了一些非常高效的循环转换。

其他一些历史事实也促成了“Java很慢”的声誉:

  • 在JIT编译(Java 1.2 / 1.3)之前,语言只能被解释,而不能被编译,因此非常慢。
  • JIT编译花费时间变得高效(每个版本都有重大改进)
  • 分类加载多年来变得更有效率。 过去在启动时效率很低,速度慢。
  • Swing和UI代码没有很好地使用本地graphics硬件。
  • 摇摆是可怕的。 我责怪AWT和Swing,为什么Java从来没有抓住桌面。
  • 大量使用库类中的同步; 不同步的版本现在可用
  • 小程序需要永久加载,因为通过networking传输完整的JAR并加载VM来启动。
  • 同步用于带来严重的性能损失(每个Java版本都对此进行了优化)。 尽pipe反思仍然很昂贵。

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

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

  2. 慢UI。 早期的摇摆很慢。 这可能没有帮助,大多数Windows用户发现默认的金属L&F丑陋的。

鉴于以上几点,难怪人们得到了“Java是慢”的印象。

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

即使代码执行和启动时间可能根本不连接,您也不会说服用户在应用程序需要8秒启动的时候才会执行代码,而不是立即启动旧的Visual Basic应用程序。

破坏第一印象是启动谣言和神话的好方法。 而谣言和神话是很难杀的。

总之,Java并不慢。 拥有“Java是缓慢的态度”的人是基于十多年前对Java的第一印象。

在阅读完整的评论说Java不慢,我只需要回答一个不同的意见。

一种语言的缓慢很大程度上取决于你对“快”的期望。 如果你认为C#是快速的,Java肯定也是快速的。 如果您的问题域与数据库或半实时处理有关,那么Java肯定也足够快。 如果您很高兴通过添加更多硬件来扩展您的应用程序,Java对您来说可能会很快。 如果你认为在5-10的规模上不断加速的因素并不值得,那么你可能会认为Java很快。

如果你在大数据集上进行数值计算,或者绑定到一个CPU资源有限的执行环境,那么在5-10的规模下不断加速将是巨大的。 即使0.5加速也可能意味着要完成500小时的计算。 在这些情况下,Java只是不允许你获得最后一个性能,而且你可能会认为Java速度很慢。

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

  1. Java真的很慢,为什么?
  2. 为什么Java被认为是慢的,即使它比许多select更快?

其中第一个或多或less是“绳子多久”的一种问题。 这归结于你的“慢”的定义。 与纯粹的解释器相比,Java非常快。 与通常编译为某种字节码的其他语言相比,dynamic编译为机器代码(例如C#或.NET上的其他任何东西)与Java相当。 与通常编译为纯机器代码的语言相比,(通常是大型的)团队只是在改进优化器(例如C,C ++,Fortran,Ada)方面工作,Java在一些方面做得很好,往往至less有点慢。

这很大程度上与实现有关 – 基本上,这归结于用户在dynamic/ JIT编译器运行时等待的事实,因此除非您有一个运行了一段时间才开始的程序,否则编译器花费大量时间进行困难的优化是很难certificate的。 因此,大多数Java(和C#等)编译器都不费力气进行真正困难的优化。 在很多情况下,优化完成的次数less于应用的优化次数。 许多优化问题都是NP完备的,所以它们所花的时间会随着问题的大小而迅速增长。 在合理范围内保持时间的一种方法是一次只将优化应用于单个function。 当只有开发人员等待编译器时,可以花费更多的时间,并将相同的优化应用到程序的更大的块中。 同样,一些优化的代码非常多(因此可能相当大)。 同样,由于用户在代码加载的同时等待(并且JVM启动时间通常是整个时间中的重要因素),所以实现必须平衡在一个地方保存的时间与在另一个地方丢失的时间 – 并且给定多less代码从多毛的优化中受益,保持JVM较小通常更有利。

第二个问题是,对于Java,你经常会得到或多或less的“一刀切”的解决scheme。 举例来说,对于许多Java开发人员来说,Swing实质上是唯一可用的窗口库。 在像C ++这样的东西中,实际上有数十个窗口库,应用程序框架等等,每个都有自己的易用性和快速执行之间的妥协,一致的外观和感觉与本机的外观和感觉等等。 唯一真正的问题是有些(如Qt)可能相当昂贵(至less在商业用途上)。

第三,用C ++编写的代码(甚至更多)更简单,更老,更成熟。 它包含了很多几十年前编写的例程的核心,当花费额外的时间优化代码是正常的,预期的行为。 这通常在代码更小更快的情况下具有真正的好处。 C ++(或C)获得了代码小而快的功劳,但它实际上更多地是开发人员的产品和编写代码的时间限制。 在某种程度上,这导致了一个自我实现的预言 – 当人们关心速度时,他们经常selectC ++,因为它有这个声望。 他们花费额外的时间和精力进行优化,并编写了新一代的快速C ++代码。

总而言之,Java的正常实现最大限度地使最大化优化成为问题。 更糟的是,在Java 可见的地方 ,窗口工具包和JVM启动时间等常常比语言本身的执行速度起到更大的作用。 在很多情况下,C和C ++也得到了真正的优化产品的功劳。

至于第二个问题,我认为这主要是工作上的人性问题。 一些狂热分子对Java的炫耀速度相当夸张。 有人尝试了一下,发现即使是一个微不足道的程序也需要几秒钟的时间才能开始,并且在运行的时候感觉很慢并且很笨拙。 很less有人可能费心费力地分析一下这些东西,其中有很多是JVM的启动时间,事实上,当他们第一次尝试时,没有任何代码已经被编译 – 一些代码正在被解释,有些正在等待编译。 更糟糕的是,即使运行速度足够快,对于大多数用户来说,外观和感觉通常会显得exception笨拙,所以即使客观的测量显示了快速的响应时间,它仍然显得笨拙。

把它们加在一起会导致一个相当简单和自然的反应:Java是缓慢,丑陋和笨拙的。 考虑到炒作真的很快,有一种反应过度的倾向,并认为这是一个可怕的缓慢,而不是(更准确的)“稍微慢一点,而且大多是在特定的情况下”。 对于编写该语言的前几个程序的开发人员而言,这通常是最糟糕的。 在大多数语言中执行“hello world”程序是即时的,但在Java中,JVM启动时会有一个容易察觉的暂停。 即使是一个纯粹的解释器,在紧密的循环中运行速度要慢得多,对于这样的代码来说,这样的代码通常也会更快,因为它可以被加载并且可以更快地开始执行。

这是Java早期(90年代中后期)的过时信息。 与以前的版本相比,Java的每个主要版本都引入了显着的加速。 随着Oracle显然将JRockit与Sun的JVM for Java 7合并,这一趋势似乎将持续下去。

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

“漫长的启动时间”的罪魁祸首是dynamic链接。 Java应用程序由编译的类组成。 每个类按名称引用其他类(对于参数types,方法调用…)。 JVM必须在启动时检查并匹配这些名称。 它是递增的,在任何时候只做它需要的部分,但是这仍然是一些工作要做。

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

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

各种优化已经被应用,包括caching技术,计算机变得更快(而且应用程序变得更“更快”,所以问题的重要性近来大大降低; 但是旧的偏见依然存在。

至于性能之后,我自己的数组访问(通常是散列函数和其他encryptionalgorithm)的紧凑计算的基准通常表明,优化的C代码比Java代码快大约3倍; 有时C只比Java快30%,有时C可以快4倍,这取决于实现的algorithm。 当“C”代码实际上汇编为大整数运算时,由于处理器提供了64×64-> 128乘法操作码,但Java不能使用,因为其最长的整数types是64位long ,所以我看到了10倍的因子。 这是一个边缘情况。 在实际情况下,I / O和内存带宽的考虑使C代码实际上比Java快三倍。

Java肯定是缓慢的,特别是对于量化工作。

我将R ,Python和C / C ++与优化的multithreadingATLAS库结合使用。 在这些语言中的每一种中,我都可以在4秒左右的时间内乘以一个3000×3000的双打matrix。 在Java中使用Colt和Parallel Colt,同样的操作需要185秒! 令人惊讶的是,尽pipe这些Java库本质上是并行的。

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

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

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

JVM速度慢,applet下载时间显着地被Java咖啡杯打上了标签,这并没有什么帮助,所以人们将这种等待与Java联系起来。 当Flash需要很长时间才能加载时,“加载”消息的品牌由Flash开发者指定,所以人们不会将Flash技术作为一个整体。

所有这一切与Java在服务器上的性能或Java在浏览器外部使用的许多其他方式无关。 但是这正是人们所看到的,以及非Java开发人员在思考Java时会记得什么。

Java的速度很慢,因为速度慢。 Java的第一个版本要么没有,要么只是很差的即时编译。 这意味着尽pipe字节码被解码,所以即使是最简单的操作(如添加两个整数),机器也必须进行各种比较,指针解引用和函数调用。 JIT编译器一直在改进; 现在,如果我不小心编写C ++代码和不小心编写Java代码,Java有时会胜过 C ++,因为JIT编译器意识到我已经得到了一些不必要的指针解引用,并将为我处理它。

如果您想查看JIT编译的差异有多大,请查看计算机语言基准游戏的解释性与非解释性基准。 (Pidigits使用一个外部库来完成所有的计算,所以基准不会改变;其他的则显示6-16倍的加速!)

所以,这是主要原因。 还有其他各种各样的原因并没有起到什么作用:最初,Java的启动时间很慢(现在是固定的); Java中的networking应用程序需要很长时间下载(现在对于宽带可用性来说更是如此,而且预计电影这样的大事情)。 UI Swing没有(现在也没有)写出性能的标准,所以它比C ++中的等效性要小得多。

Java在一天之中很慢。 由于几代性能的提高 ,它变得更快了 。 最后我听说,它通常在C#速度的10%以内 – 有时更快,有时更慢。

Java小程序启动仍然很慢,因为你必须启动一个完整的JVM,它必须加载所有的类。 有点像启动另一台电脑。 一旦JVM启动,速度相当快,但启动通常是人们记得的。

另外, 至less有一些人永远不会相信Java的可行性。

斯特凡诺:

从一开始我就一直在使用Java,所以从我的angular度来看,缓慢的名声是由无响应和慢GUI前端(AWT,然后是Swing)以及在Applets中创build的,可能是因为VM的。

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

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

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

在主streamJava之外还有许多应该考虑的事情,比如Realtime Java或者像Javolution一样提高速度的特殊机制,以及像gcj这样的前期编译(Ahead-Of-Time)。 此外,还有一些IC可以直接执行Java Bytecode,例如目前的iPhone和iPod的ARM Jazelle 。

我认为一般来说,今天这是一个政治决定(就像iPhone / iPod上没有Java支持一样),并且决定反对Java作为一种语言(因为很多人认为它太冗长)。

然而,Java VM现在还有很多其他语言(例如Python,Ruby,JavaScript,Groovy,Scala等),可能是另一种select。

就我个人而言,我将继续享受它作为一个灵活可靠的平台,具有出色的工具和库可用性,允许从最小的设备(例如JavaCard)到最大的服务器都可以工作。

推出面团的锤子要比其他许多工具慢得多。 不要让锤子“变慢”,对于devise要做的任务也不那么有用。

作为一种通用的编程语言,Java与许多编程任务(如果不是最多的话)相当。 有一些特殊的,简单的testing,Java在不太复杂的语言中不会超越手写代码的解决scheme,而是“更接近金属”的语言。

但是当涉及到“真实世界的应用程序”时,Java通常是正确的工具。 现在,这就是说,没有什么会阻止开发人员使用ANY工具制作性能较差的解决scheme。 滥用工具是一个众所周知的问题(只要看看PHP和VB的声誉)。 但是,Java(大部分)干净的devise和语法对减less滥用做了很多工作。

Java是一种高级语言,它现在的声誉是与其他可比的高级语言相媲美。

  1. 它具有dynamic绑定语义。 与非虚拟方法被编译为函数调用的C ++相比,即使是世界上最好的Java编译器也必须生成效率较低的代码。 但它也是一个更清洁,更高级的语义。

  2. 我不记得细节,但是在Java的早期我听说每个Java对象都有一个互斥,每个方法都会被获取和释放。 这样可以更好地适应并发性,但是不幸的是,每个对象只是一个互斥对象,不能保护您不受比赛或死锁的困扰,也不能保护并发程序中可能发生的任何不好的事情。 这个部分如果是真的,有点天真,但是它是出于好意。 如果您对这方面有更多了解,请随时填写详细信息。

  3. Java是高级语言的另一种方式是通过垃圾收集 。 垃圾收集可能比malloc慢,对于一次分配所有需要的内存的程序是free的。 问题是,在没有垃圾收集的语言中,程序员倾向于写程序来分配所有他们需要的内存,如果结果是一些任意的最大大小常量被溢出,则会失败。 所以比较是橙子苹果。 当程序员努力编写和debugging非GC语言的链式结构dynamic分配程序时,他们有时会发现他们的程序不再比GC语言更快,因为mallocfree是不免费的! 他们也有开销…另外,没有一个GC力量来指定谁可以释放什么,而且必须指定谁释放什么,有时会强制你复制 – 当几个函数需要这些数据时,并不清楚将最后使用它 – 而在GC语言中则不需要复制。

在九十年代中期,当Java成为主stream时,C ++是主stream语言,networking还是比较新的。 而且,JVM和GC在主stream开发中是相对较新的概念。 早期的JVM比较慢(与裸机上运行的C ++相比),而且还有时会导致垃圾收集暂停,这导致了Java的声誉变慢。

许多Java桌面应用程序(这些时间:像Eclipse这样的东西)具有不良的GUI响应能力,这可能是由于高内存消耗和类加载器可以执行大量IO的事实。 情况正在改善,但是几年前更糟。

许多(大多数)人喜欢做一般化,所以他们说“Java很慢”,因为他们认为应用程序在与它们交互时很慢。

Java应用程序的主要问题在于,由于库运行时库的规模很大 ,所以它是巨大的 。 巨大的程序在内存中占据很大的比例,往往会交换,意味着它们变得缓慢。

Sun JVM很大的原因是因为它有一个非常好的字节码解释器,它通过跟踪很多事情来工作。 这意味着很多数据,这意味着记忆。

你可能想看看jamvm虚拟机,它是一个相当快的解释器(非本地代码),非常小。 它甚至开始快速。

正如帕斯卡尔所说,Java与其他高级语言是一致的。 然而,作为在Windows 98上使用原始JVM的人,在Java虚拟机提供抽象级别的时候,我们应该说是痛苦的。

基本上,这是在JVM中我们认为理所当然的软件仿真,没有什么优化。

人们通常走出“解释”的路线。 因为曾经有一次,糟糕的新闻被那些甩掉Java的人“传得太慢”而无法回头testing新版本。

或者“人是白痴”是一个更好的答案。

我认为有一天,也许不是在不久的将来,由于JIT编译器可以大量使用运行时间,所以JIT编译的语言在任何方面都会超过编译语言(可能不是启动时间/内存消耗)行为和他们运行的平台。