代码之家  ›  专栏  ›  技术社区  ›  Stefano Borini

Java真的很慢吗?

  •  181
  • Stefano Borini  · 技术社区  · 16 年前

    爪哇有 some degree of reputation for being slow .

    • Java真的很慢吗?
    • 如果是,为什么?瓶颈在哪里?是因为效率低下的JVM吗?垃圾收集?纯字节码库而不是JNI封装的C代码?许多其他语言都有这些特性,但它们并不以缓慢著称。
    19 回复  |  直到 10 年前
        1
  •  236
  •   Peter Mortensen Pieter Jan Bonestroo    10 年前

    现代Java是最快的语言之一,尽管它仍然是内存堆。爪哇 由于VM启动需要很长时间而以速度慢著称。

    如果你仍然认为Java是慢的 ,请参见 the benchmarks game 结果。在一个超前编译语言(C,FORTRAN等)中编写的紧密优化的代码可以打败它;然而,Java可以比PHP、Ruby、Python快10倍以上。在某些领域,它可以打败常用编译语言(如果使用标准库)。

    现在没有“慢速”Java应用的借口。 与语言相比,开发人员和遗留代码/库要负更多的责任。而且,责备任何“企业”。

    公平地对待“Java慢”人群,这里是缓慢的区域(更新为2013):

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

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

    • 阵列访问比C慢一点, 由于边界检查。惩罚是大的,但现在很小(Java 7优化了大量的冗余边界检查)。

    • 缺少任意的内存访问可能会使某些I/O和位级处理速度变慢(例如压缩/解压)。 这是目前大多数高级语言的安全特性。

    • Java使用了比C更多的内存, 如果您的应用程序是内存绑定的或内存带宽绑定的(缓存等),这会使它变慢。另一方面,分配/解除分配速度极快(高度优化)。 由于对象和使用 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。子串()优化,因为人们愚蠢地使用它,并获得内存泄漏。

    • 阵列拷贝高度优化。 在最新的版本中,Java使用手工调整的汇编语言来进行Salay.ArayIcRead。结果是,在arraycopy/memcopy繁重的操作中,我看到我的代码在C语言中以合理的裕度击败了等价的代码。

    • JIT编译器很擅长使用 L1/L2 隐藏物 . 提前编译的程序无法实时调整其代码,使其适应运行在其上的特定CPU和系统。JIT以这种方式提供一些非常有效的循环转换。

        2
  •  49
  •   Peter Mortensen Pieter Jan Bonestroo    10 年前

    1. Swing

    Visual Basic 应用程序,这两点是应用程序中最明显的东西,这是您对应用程序的第一印象(除非它是非GUI应用程序,在这种情况下只有1个)。适用。)

    当应用程序需要8秒才能启动时,您不会说服用户“它执行代码非常快”,而他的旧Visual Basic应用程序则会立即启动,即使代码执行和启动时间可能根本没有连接。

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

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

        3
  •  40
  •   Sami    16 年前

    读完一篇充满评论的页面,说Java不是慢的,我只需要用不同的观点回答。

    语言的缓慢很大程度上取决于你对“快”的期望。如果你认为C是快的,Java当然也很快。如果您的问题域与数据库或半实时处理相关,Java也肯定足够快。如果您乐于通过添加更多的硬件来扩展应用程序,Java可能对您来说很快。如果你认为一个常数因子在5-10的范围内加速是不值得的,那么你很可能会考虑Java快速。

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

        4
  •  33
  •   Jerry Coffin    16 年前

    你似乎问了两个截然不同的问题:

    1. Java真的很慢吗?如果是,为什么?
    2. 为什么Java被认为是慢的,尽管它比许多其他选择要快?

    第一个问题或多或少是一个“绳子有多长”的问题。这可以归结为你对“慢”的定义。与纯解释器相比,Java的速度非常快。与其他(通常)编译成某种字节码的语言相比,然后动态编译成机器代码(例如,C或其他任何.NET)Java都是大致相同的。与通常编译为纯机器代码的语言相比,Java(艾达、C++、FORTRAN、Fortran)中的(通常是大的)团队都在改进它们的优化器(例如,C、C++、FORTRAN、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的启动时间,而且事实上,当他们第一次尝试时,还没有编译任何代码——一些代码正在被解释,还有一些在等待时被编译。更糟糕的是,即使它运行的足够快,外观和感觉对大多数用户来说通常都是陌生和笨拙的,所以即使客观的测量显示响应时间很快,它仍然显得笨拙。

    把这些加在一起会导致一种相当简单和自然的反应:爪哇是缓慢、丑陋和笨拙的。考虑到宣传说它真的很快,有一种过度反应的倾向,并认为它是 可怕地 慢,而不是(更准确地说)“稍慢,主要是在特定的情况下。”这对于用这种语言编写前几个程序的开发人员来说通常是最糟糕的。在大多数语言中执行“Hello World”程序似乎是即时的,但在爪哇,当JVM启动时,有一个容易察觉的停顿。即使是一个纯解释器,在紧凑的循环上运行的速度也要慢得多,对于类似这样的代码来说,这样的解释器仍然会出现得更快,仅仅是因为它可以更快地加载并开始执行。

        5
  •  16
  •   Dan Dyer    16 年前

    这是爪哇早期(90年代中期到90年代)的过时信息。与以前版本相比,Java的每一个主要版本都引入了显著的加速。由于Oracle显然将JROCKIT与Sun的JVM合并为Java 7,这一趋势看来将继续下去。

    与许多其他流行的现代语言(Python、Ruby、PHP)相比,Java对于大多数用途来说实际上更快。它不太匹配C或C++,但是对于许多任务来说,它已经足够接近了。真正的性能问题应该是它最终使用了多少内存。

        6
  •  14
  •   Thomas Pornin    16 年前

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

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

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

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

    至于后来的性能,我自己对数组访问(主要是散列函数和其他密码算法)的紧凑计算的基准通常显示优化的C代码比Java代码快约3X;有时C比Java快30%,有时C可以是4X更快,这取决于实现的算法。当“C”代码实际上是用于大整数运算的汇编时,我看到了一个10x因子,这是因为处理器提供的64×64和128乘运算码,但Java不能使用,因为它的最长整数类型是64位。 long . 这是一个边缘案例。在实际情况下,考虑到I/O和内存带宽,C代码无法 真正地 比Java快三倍。

        7
  •  14
  •   Peter Mortensen Pieter Jan Bonestroo    10 年前

    Java无疑是缓慢的,特别是对于定量工作。

    我结合使用 R 具有优化的多线程的Python和C/C++ ATLAS 图书馆。在每一种语言中,我都可以用一个3000乘3000的双精度矩阵在4秒钟内与自身相乘。在JAVA中使用柯尔特和平行小马,同样的操作需要185秒!尽管这些Java库本质上是并行的,但却令人惊讶。

    总之,纯Java不适合于定量工作。Jblas似乎是最好的线性代数库的Java,因为它使用阿特拉斯。

    我的机器是HP Core 2 Duo 3 GB内存。我用64位 Ubuntu 10.04 (Lucid Lynx)

        8
  •  10
  •   Peter Mortensen Pieter Jan Bonestroo    10 年前

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

    缓慢的JVM旋转和applet下载时间明显地被Java咖啡杯所标记,这是无济于事的,所以人们把等待与Java联系起来。什么时候? Flash 加载需要很长时间,“加载”消息的品牌是由Flash开发人员指定的,因此人们不必责怪整个Flash技术。

    所有这些都与Java在服务器上的性能无关,或者与Java在浏览器之外使用的许多其他方式无关。但这是人们看到的,非Java开发人员在想到Java的时候会记住什么。

        9
  •  9
  •   Rex Kerr    16 年前

    Java具有慢的名声,因为它 慢。Java的第一个版本在编译时没有或相当差。这意味着代码,尽管字节码,正在被解释,所以即使是最简单的操作(如添加两个整数),机器也必须进行各种比较、指针解引用和函数调用。JIT编译器一直在改进;现在,如果我粗心地编写C++代码和Java代码时,Java有时会 表现出色 C++,因为JIT编译器意识到我有一些不必要的指针去引用,并且会为我处理。

    如果您想了解JIT编译有多大的区别,请查看 Computer Languages Benchmark Game . (pidigits使用一个外部库来进行所有计算,这样基准就不会改变;其他的则显示6-16倍的加速!)

    所以,这是主要原因。还有很多其他的、不太重要的原因没有帮助:最初,Java启动时间很慢(现在是固定的);Java中的Web应用程序要花很长时间才能下载(更不用说现在广泛使用的宽带,以及像电影一样的大事物);UI摆动不是(而且还没有)以性能来记的。o比在C++中的等价物少得多。

        10
  •  6
  •   Kaleb Brasee    16 年前

    Java是缓慢的,回到白天。由于 a few generations of performance enhancements . 据我所知,它通常在C速度的10%以内——有时更快,有时更慢。

    Java Applet的启动仍然很慢,因为您必须启动一个完整的JVM,它必须加载它的所有类。有点像启动另一台计算机。一旦JVM启动,它就相当快,但是启动通常是人们记忆中的事情。

    此外,还有 at least a few people 这将永远不会相信Java的可行性。

        11
  •  6
  •   Dieter    16 年前

    斯蒂法诺:

    从一开始我就一直在使用Java,所以从我的角度来看,慢的名声是由非响应的和慢的GUI前端(AWT,然后Swing)和applet生成的,这可能是因为VM的额外的慢启动时间。

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

    后端的Java和计算水平并不是那么慢。 Colt 是最好的例子之一:

    最新稳定的Colt版本打破了JDK IBM-1.4.1、Redhat 9.0、2X Intelxeon@2.8GHz上的1.9gFlop/s屏障。

    主流Java之外有很多东西需要考虑,比如实时Java或特殊机制来提高速度。 Javolution 以及提前编译(如gcj)。还有,可以直接执行Java字节码的IC,例如在当前iPhone和iPod中的一个。 ARM Jazelle .

    我认为,今天,这是一个政治决策(就像iPhone上没有Java支持一样),以及对Java作为语言的决定(因为很多人认为它太冗长了)。

    然而,现在有许多其他Java语言的语言(例如Python、Ruby、JavaScript、Groovy、Scala等),这可能是另一种选择。

    就我个人而言,我仍然喜欢它作为一个灵活可靠的平台,拥有出色的工具和库可用性,它允许人们使用从最小的设备(如javacard)到最大的服务器的所有东西。

        12
  •  4
  •   Eva    12 年前

    用锤子擀面团比用其他工具要慢得多。不会使锤子“变慢”,也不会对它设计的任务不太有用。

    作为一种通用的编程语言,Java与许多编程任务(如果不是大多数)相当。有一些特殊的、琐碎的测试,Java将无法在较复杂的语言中胜过手工编码的解决方案,那些“更接近于金属”的语言。

    但是,当涉及到“现实世界应用”时,Java常常是正确的工具。现在,也就是说,没有什么能阻止开发人员使用任何工具来制定执行缓慢的解决方案。滥用工具是一个众所周知的问题(看看PHP和VB的声誉)。然而,Java(主要是)干净的设计和语法确实有助于减少误用。

        13
  •  3
  •   Pascal Cuoq    16 年前

    Java是一种高级语言,它现在的声誉是与其他类似的高级语言具有同等的性能。

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

    2. 我不记得这些细节,但在Java早期,我听说每一个Java对象都有一个互斥体,每个方法都要获取和释放。这会使它更好地适应并发性,尽管不幸的是,每个对象只有一个互斥体并不能保护您免受竞争、死锁或并发程序中可能发生的任何坏事情的影响。那部分,如果是真的,是有点幼稚,但它来自善意。如果你对这方面了解得更多,请随时向我介绍细节。

    3. Java是高级语言的另一种方式是通过 Garbage-Collection . 垃圾收集可能比 malloc free 对于一次分配所有所需内存并使用这些内存的程序。问题是,在没有垃圾收集的语言中,程序员倾向于编写 只有 一次分配所有所需内存的程序,如果发现某个任意的最大大小常量溢出,则会失败。所以比较是苹果和桔子。当程序员努力用非GC语言动态分配链接结构来编写和调试程序时,他们有时会发现他们的程序不再比GC语言快,因为 马洛克 自由的 不是免费的!他们也有开销…另外,没有GC强制指定谁释放什么,并且必须指定谁释放什么,有时会强制您在几个功能需要数据时进行复制,并且不清楚最后使用哪个功能,而在GC语言中复制是不必要的。

        14
  •  2
  •   Ken Liu    10 年前

    在90年代中期,当Java进入主流时,C++是主流语言,而Web仍然是相当新的。此外,在主流开发中,JVM和GC是相对较新的概念。早期的JVM有点慢(与在裸金属上运行的C++相比),同时也遭受了长时间的垃圾收集停顿,这导致Java的声誉很慢。

        15
  •  1
  •   Wojciech Kaczmarek    16 年前

    许多Java桌面应用程序(这些时间:像Eclipse之类的东西)具有很差的GUI响应性,这可能是由于高内存消耗和类加载器可以做很多IO的事实。 它在改善,但几年前更糟了。

    很多(大多数)人喜欢做概括,所以他们说“Java是慢的”,因为他们认为应用程序与他们交互时是缓慢的。

        16
  •  1
  •   Thorbjørn Ravn Andersen    15 年前

    Java应用程序的主要问题是它是 巨大的 因为库存运行库的规模很大。巨大的程序在内存中填充了大量的内容,并倾向于交换,这意味着它们会变慢。

    Sun JVM之所以很大,是因为它有一个非常好的字节代码解释器,可以通过跟踪很多事情来工作。这意味着大量的数据,也就是内存。

    您可能想看看jamvm虚拟机,它是一个相当快的解释器(没有本机代码),而且非常小。它甚至启动得很快。

        17
  •  1
  •   Peter Mortensen Pieter Jan Bonestroo    10 年前

    正如Pascal所言,Java与其他高级语言相当。但是,作为与最初的JVM合作的人, Windows 98 在那时,Java虚拟机提供的抽象级别,我们应该说是痛苦的。

    基本上,我们今天在JVM中认为这是一种软件仿真,几乎没有优化或者没有优化。

        18
  •  0
  •   Mr. Boy    16 年前

    人们通常会说出“它是被解释的”这句话。因为有一次,坏消息会被那些把Java扔出“太慢”的人传下来,并且再也没有测试新版本。

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

        19
  •  0
  •   helpermethod    16 年前

    我认为有一天,也许在不久的将来,JIT编译语言在任何方面都会优于编译语言(可能不是启动时间/内存消耗),因为JIT编译器可以充分利用运行时行为和运行平台。