Java真的很慢吗?


180

Java 因其速度慢而享有一定声誉

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

35
人们变得如此紧张……看不出这是如何主观的,也不是争论的。我想知道诸如“为什么气泡排序速度慢”之类的问题是否会获得相同的结果。我问了一个技术性问题,并想得到技术性答案(我得到了),但是以主观和辩论性的方式结束这个问题是荒谬的。
Stefano Borini 2010年

1
我已经阅读了大多数的热门评论,但似乎没有一个能解决一个明显的事实,即基于C#GUI的桌面应用程序的运行速度比任何基于Java GUI的桌面应用程序(包括现代的)要快得多。
BobTurbo 2011年

3
作为一个在Java中处理过.net Webforms,.net MVC,PHP,Rails,Django和除Spring(我听说过很好)之外的所有其他内容的客户端Web开发人员,我希望性能/体系结构不佳从Java团队构建的后端开始。我怀疑真正的问题不是基准测试,而是仅存在一群普通的Java开发人员的问题。那不是语言的错。真正磨练自己的技能并学习Java以外的语言的不是Java开发人员的错。但是,这可能是Sun,证书,90年代和整个IT行业的错。
Erik Reppen

Answers:


236

现代Java是最快的语言之一,即使它仍然是内存消耗大的人。Java的,因为它曾经花费很长的时间VM启动正在缓慢的声誉。

如果您仍然认为Java运行缓慢,请参见基准测试结果。用预先编译的语言(C,Fortran等)编写的经过严格优化的代码可以胜过它;但是,Java的速度可以是PHP,Ruby,Python等的10倍以上。在某些方面,它可以击败常见的编译语言(如果它们使用标准库)。

现在没有“慢” Java应用程序的借口。归咎于开发人员和遗留代码/库,而不仅仅是语言。另外,也要怪任何“企业”。

为了公平地对待“ Java缓慢”人群,以下是仍然缓慢的区域(2013年更新):

  • 库的编写通常是出于“正确性”和可读性,而不是性能。在我看来,这是Java信誉不佳的主要原因,尤其是服务器端。这使String问题成倍恶化。一些简单的错误很常见:对象通常用于代替基元,从而降低性能并增加内存使用量。许多Java库(包括标准库)都会频繁创建String,而不是重用可变或更简单的格式(char []或StringBuffer)。这很慢,并且会产生大量垃圾以便以后收集。为了解决这个问题,我建议开发人员尽可能使用原始集合,尤其是Javalution的库。

  • 字符串操作有点慢。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 比大多数其他语言都快

  • 内存分配和取消分配既快速又便宜。我见过这样的情况:分配新的多kB阵列比重用缓存的阵列要快20%(或更多!)。

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

  • 方法调用基本上是免费的,并且在某些情况下比大型方法代码要快。热点编译器使用的执行信息来优化方法调用,具有非常高效的内联。通过使用其他执行信息,它有时可能会比提前编译器甚至在手动插入中(在极少数情况下)都更胜一筹。与C / C ++相比,在C / C ++中,如果编译器决定不内联,则方法调用的性能会受到较小的影响。

  • 同步和多线程既简单又高效。从一开始,Java就被设计为可感知线程的。现代计算机通常具有多个内核,并且由于该语言内置了线程功能,因此您可以轻松利用。与标准的单线程C代码相比,基本上速度提高了100%至300%。是的,精心编写的C线程和库可以解决这个问题,但这对程序员来说是很多额外的工作。

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

  • 阵列复制已高度优化。在最新版本中,Java对System.arraycopy使用手动调整的汇编程序。结果是,在大量进行arraycopy / memcopy的操作中,我已经看到我的代码以合理的幅度击败了C语言中的等效代码。

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

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

  • 在JIT编译(Java 1.2 / 1.3)之前,该语言仅被解释而不被编译,因此非常慢。
  • JIT编译需要时间才能变得高效(每个版本都有重大改进)
  • 多年来,类加载已变得更加高效。在启动过程中,它以前效率很低而且很慢。
  • Swing和UI代码不能很好地使用本机图形硬件。
  • 摇摆真可怕。我将AWT和Swing归咎于Java为什么从不流行于桌面。
  • 在库类中大量使用同步;现在可以使用非同步版本
  • 由于要通过网络传输完整的JAR并加载VM以进行引导,因此Applet的加载需要花费很长时间。
  • 同步曾经带来了沉重的性能损失(每个Java版本都对此进行了优化)。但是,反思仍然是昂贵的。

49
Object instantiation and object-oriented features are blazing fast to use (faster than C++ in many cases) because they're designed in from the beginning.并且Collections are fast. Standard Java beats standard C/C++ in this area, even for most optimized C code.没有任何在此链接的证据支持的野蛮主张。
Sjoerd

8
@Sjoerd-这些主张几乎没有什么野蛮的-对我来说,它们很明显,对那些了解C / C ++与Java中默认内存系统的体系结构差异的人来说,它应该是显而易见的。你可以,如果你写你自己的内存处理程序(用的东西,如免费名单,内存池,等等)做的更好静止或使用一个库,实现这样。
Rex Kerr

15
@Rex Kerr-如果可以使用例如堆栈进行分配,为什么还要使用内存处理程序?您将堆内存分配与对象实例化混淆了。
Sjoerd

20
@Rex Kerr-基本上,您声称因为Java中的所有内容都涉及在堆上分配内存,并且由于Java中Java的堆上Java分配比C ++更快,因此Java中的所有内容都更快。这是给您的一些新闻:在C ++中,很多情况下您无需在堆上分配内存即可!
Sjoerd

10
@Sjoerd-我在哪里说Java 中的所有内容都更快?只是读我的话。我说了我的意思,并且已经解决了您在上一次评论中说的所有内容。
雷克斯·克尔

49

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

  1. 虚拟机启动时间慢。与本机应用程序相比,早期的Java实现花费很长时间来启动和加载需求库和应用程序。

  2. 慢的用户界面。早期的摇摆很慢。大多数Windows用户也很难找到默认的Metal L&F,这可能也无济于事。

考虑到以上几点,难怪人们会收到“ Java速度慢”的印象。

对于习惯于开发本机应用程序甚至Visual Basic应用程序的用户或开发人员,这两点是应用程序中最明显的东西,这是您对应用程序的第一印象(除非它是非GUI应用程序,仅适用于1.)。

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

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

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


3
Java几年前非常慢,但是在最近的基准测试中,它的运行速度几乎与C / C ++一样快,并且在某些情况下,它运行得更快。
ChadNC 2010年

23
Macbook上OSX 10.6上的Java应用程序比用Objective-C编写的应用程序启动慢得多。有什么证据可以加快启动时间?
Zan Lynx 2010年

2
减压绝对不是性能问题。我的计算机在1992年启动程序时解压缩了可执行文件,从而比从硬盘驱动器加载更长的文件的性能有所提高。在过去的几年中,CPU与硬盘之间的差距已经大大增加。但是,对于rt.jar使用zip存档格式存在问题(为什么?!!),并且所包含的类文件未链接(nuts !!)。
Tom Hawtin-大头钉

5
@Zan:请注意,Mac OS X的JVM由Apple编写(或至少改编了)。Sun已经投入了很多时间来缩短它们所支持的平台(Windows,Linux和Solaris)上的启动时间,但是他们无法在Mac OS x上这样做(因为它们不维护该端口)。这可能是苹果不可能/没到Mac OS X的应用/端口的所有这些优化
约阿希姆·绍尔

1
我不认为Java会很慢(我知道有一个游戏制作人在其中制作游戏);出于用户界面的原因而已。我见过的单个“常规” Java应用程序都没有一个像样的,完全正常的UI。
RCIX

40

阅读完充满评论的页面后说Java并不慢,我只需要以不同的观点回答即可。

语言的慢速很大程度上取决于您对“快速”的期望。如果您认为C#很快,那么Java当然也很快。如果您的问题域与数据库或半实时处理有关,那么Java当然也足够快。如果您愿意通过添加更多硬件来扩展应用程序,则Java可能对您来说很快。如果您认为5到10的常数因子加速是不值得的,那么您可能会认为Java快速。

如果您在大型数据集上进行数值计算,或者绑定到执行环境,在该环境中CPU资源是有限的,那么5-10的规模的持续加速将是巨大的。即使速度提高0.5,也可能减少500小时才能完成计算。在这些情况下,Java只是不允许您获得最后的性能,您可能会认为Java速度很慢。


2
同意,并且在整个帖子中+1,因为您提出了一个正确的观点,但是,例如,C ++具有不同的名声:难以调试,容易使人失望,但我很少听说C ++这么慢我听说过Java。
Stefano Borini 2010年

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启动,有一个容易察觉的暂停。即使是在紧密循环上运行得慢得多的纯解释器,对于这样的代码,这样的解释器仍常常显得更快,这仅仅是因为它可以被加载并可以更快地开始执行。


16

它是Java早期(1990年代中后期)的过时信息。与先前版本相比,Java的每个主要版本都引入了显着的提速。甲骨文显然将JRockit与Sun的Java 7 JVM合并在一起,这种趋势似乎将继续。

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


14

“长时间启动”的主要原因是动态链接。Java应用程序由编译的类组成。每个类都通过name引用其他类(用于参数类型,方法调用...)。JVM必须在启动时检查并匹配这些名称。它以增量方式执行此操作,仅在任何给定时间执行所需的部分,但这仍然是一些工作。

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

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

已经应用了各种优化方法,包括缓存技术,并且计算机的运行速度越来越快(与应用程序变得“更大”相比,计算机变得“更快”),因此问题的重要性最近大大降低了。但是旧的偏见依然存在。

至于之后的性能,我自己对带有数组访问的紧凑计算(主要是哈希函数和其他密码算法)的基准测试通常表明,优化的C代码比Java代码快约3倍;有时,C仅比Java快30%,有时C可以比Java快4倍,具体取决于实现的算法。由于处理器提供了64x64-> 128乘法操作码,但Java不能使用,因为最长的整数类型是64位,因此我实际上看到了“ C”代码为大整数算术进行汇编时的10倍因子long。这是一个极端的情况。在实际条件下,出于I / O和内存带宽的考虑,C代码的速度实际上比Java快三倍。


嗯...我想现在大多数C库也都是动态链接的。还是您说的是不同的东西?
肖恩·麦克米伦

4
@Sean:对C的动态链接发生在“外部符号”上:在一个DLL中使用而在另一个DLL中定义的功能。一个典型的C应用程序将使用多个DLL。对于Java,动态链接发生在所有类中的所有方法上:在典型的Java应用程序(包括标准库)中有成千上万的方法。在C语言世界中,大多数链接(所有不跨越DLL边界的链接)都在编译时解决,但只有一小部分需要在运行时解决。
Thomas Pornin 2011年

14

Java肯定很慢,特别是对于定量工作而言。

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

因此,总而言之,纯Java不适合进行定量工作。Jblas似乎是Java的最佳线性代数库,因为它使用ATLAS。

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


根据我的上述评论,我使用JAMA执行了相同的矩阵乘法运算,大约花费了50秒。与其他语言相比仍然太慢。
Hamaad Shah,2010年

7
在通过JNI调用的库中执行乘法时,Java花了多长时间。鉴于您可以在C / C ++中进行的任何操作,都可以使用JNI(添加几百纳秒)来完成,因此裕度相对较小。我猜您的R和Python矩阵乘法不是用R或Python编写的,只是从这些语言中调用的。
彼得·劳瑞

2
出于好奇,您是否进行了任何分析以识别代码中是否存在某些热点(类型转换/自动装箱)?
托尔比约恩Ravn的安德森

10

对于大多数人而言,与Java交互的速度慢。我们都已经看到咖啡杯在小程序出现之前在浏览器中旋转。启动JVM和下载applet二进制文件需要花费一些时间,这以一种值得注意的方式影响了用户体验。

Java咖啡杯明显标记了缓慢的JVM旋转和applet下载时间,这无济于事,因此人们将等待与Java关联。当Flash需要很长时间才能加载时,Flash开发人员会指定“正在加载”消息的商标,因此人们不会将Flash技术作为一个整体。

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


9

Java之所以被称为慢是因为它慢。Java的第一个版本没有“准时制”编译,甚至没有。这意味着该代码尽管是字节码,但仍在被解释,因此即使对于最简单的操作(如加两个整数),机器也必须进行各种比较,指针取消引用和函数调用。JIT编译器一直在不断改进;现在,如果我不小心编写C ++代码和不小心编写Java代码,Java有时会胜过 C ++,因为JIT编译器意识到我有一些不必要的指针反引用,并且会为我处理。

如果您想了解JIT编译的差异有多大,请在Computer Languages Benchmark Game上查看解释基准和未解释基准。(Pidigits使用外部库进行所有计算,因此基准不会改变;其他显示6-16倍的加速!)

所以,这就是主要原因。还有其他许多次要的问题也无济于事:最初,Java启动时间很长(现已确定);用Java编写的Web应用程序需要花费很长时间才能下载(现在,在可广泛访问的宽带上,并且预计会有大片电影之类的东西,现在情况就不那么如此了);UI Swing并不是(现在也没有)考虑性能而编写的,因此它比例如C ++中的等效项要快得多。


6

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

Java applet的启动仍然很慢,因为您必须启动整个JVM,该JVM必须加载所有类。有点像启动另一台计算机。JVM启动后,启动速度相当快,但是启动通常是人们记住的。

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


1
不幸的是,JVM启动仍然比CLR启动慢得多。这是因为太阳已经拖了其在最糟糕的莫过于双脚释放的Java 7,所以我们坚持用增量补丁到4岁的Java 6
BobMcGee

3
哇,Java 6已有4岁了???是的,我想是的(如果算上beta的话)。对我来说仍然很陌生-我刚刚停止使用1.4。
Kaleb Brasee 2010年

Java 1.4可用,但有点奇怪,因为1.5和1.6增加了许多性能提升和语法糖。从那时起,就引入了边界检查和System.arraycopy优化。因此,进行了许多同步改进。我认为公平地说1.4确实很慢。
BobMcGee 2010年

大声笑,我知道-每次我必须手动进行迭代或使用数组而不是通用列表时,我都想将笔记本电脑分成两半...多年来,IBM实际上已经在WAS 6.1上提供了Java 5。一直停留在WAS 6.0上:(自从我将Java 5/6运用于我自己的东西以来,我一直在使用它,但受到工作中的旧服务器版本的限制。性能从1.4到最新版本都有两位数的提高–很多事情,我
都很

6

斯特凡诺:

从一开始我就一直在使用Java,因此从我的角度来看,缓慢的成名是由无响应和缓慢的GUI前端(AWT,然后是Swing)以及Applet造成的,这可能是由于Java的额外缓慢启动时间所致。虚拟机。

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

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

最新的稳定Colt版本在JDK ibm-1.4.1,RedHat 9.0、2x IntelXeon@2.8 GHz上突破了1.9 Gflop / s的要求。

在主流Java之外,还应考虑许多事情,例如实时Java或提高速度的特殊机制(例如Javolution)以及Ahead-Of-Time编译(例如gcj)。另外,有些IC可以直接执行Java字节码,例如当前iPhone和iPod ARM Jazelle中的IC 。

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

但是,当今有许多其他的Java VM语言(例如Python,Ruby,JavaScript,Groovy,Scala等)可以替代。

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


好的,因此来自GUI工具包的另一个不好的声誉。当然,我认为,由于现代JVM使用本机窗口小部件,因此它们可以挂接到OS库中,对吗?还是使用AWT / Swing渲染主机平台的外观?
Stefano Borini 2010年

Stefano:Swing实际上基于小部件的非本地通用渲染的思想,因此您的假设有点错误。实际上,这是一种“可插入的外观”机制,它允许Swing组件模拟本机组件的外观。如果您正在寻找类似的东西,那么您可能想要检出SWT(eclipse.org/swt),它确实会挂接到本机OS上,并使用通过JNI使用的本机小部件(这被称为瓶颈)。
Dieter

如今,Java2D(用于Swing)非常快,使用本机窗口小部件(SWT)不会带来性能上的好处。至少,这是六个月前我决定学习Swing还是SWT时所读的内容。
路易吉·普林格

4

锤出面团的锤子比许多其他工具慢得多。不会使锤子“变慢”,也不会使锤子在设计要执行的任务中有用。

作为一种通用的编程语言,Java在许多编程任务上与许多(如果不是大多数)一样。在某些特定的琐碎测试中,Java不会以较不复杂的语言(“更接近金属”)胜过手工编码的解决方案。

但是当涉及到“现实世界的应用程序”时,Java通常是正确的工具。话虽如此,但没有什么可以阻止开发人员使用ANY工具来制作性能缓慢的解决方案。滥用工具是一个众所周知的问题(仅查看PHP和VB的声誉)。但是,Java的(主要是)简洁的设计和语法确实在减少误操作方面起到了很大作用。


3

Java是一种高级语言,如今其声誉是要与其他可比较的高级语言相提并论。

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

  2. 我不记得详细信息,但是在Java的早期,我听说每个Java对象都有一个互斥体,每种方法都需要获取并释放该互斥体。尽管不幸的是,每个对象只有一个互斥体并不能保护您免于竞争或死锁或并发程序中可能发生的任何不良影响,但这往往会使它更适合于并发。那部分,如果是真的,虽然有点天真,但这是出于善意。如果您对这方面有更多了解,请随时填写我的详细信息。

  3. Java是高级语言的另一种方式是拥有Garbage-Collection。垃圾收集可能会慢malloc而且free对于分配一次他们需要的所有存储器和工作与程序。问题是,在没有垃圾回收的语言中,程序员往往编写一次分配所有需要的内存的程序,如果发现某个最大大小常量已溢出,该程序将失败。因此,比较是苹果与橘子。当程序员作出努力与非GC语言链结构的动态分配编写和调试程序,它们有时会发现,他们的计划是不超过在GC语言更快,因为mallocfree不是免费的!他们也有开销。此外,没有GC会强制指定谁释放什么,而又必须指定谁释放什么,这有时会迫使您进行复制-当多个功能需要数据并且不清楚哪个将在最后使用它-而无需使用GC语言进行复制。


1.对于HotSpot来说可能不正确。2.仅当您将该方法标记为已同步时。
Winston Ewert 2010年

1
1.编译器不会优化代码,但是JVM足够聪明,可以动态确定通常只调用一个或两个虚拟方法,并且可以静态调用它们,甚至可以内联它们。我很确定C ++不能内联虚拟方法。2.每个Java对象都有一个锁。每个对象的开销很小(大约一个字节),但如果不使用,影响很小。3.在Java中,您可以立即分配所需的所有对象。这可以为您提供一整天都不会GC的应用程序。;)Java的GC是隐式多线程的,需要在C ++中进行特殊的准备。
彼得·劳瑞

C ++可以内联虚拟调用,但是Java可以在更多情况下进行虚拟调用,并且在优化大形调用站点方面也更强大。
PiotrKołaczkowski15年

2

在90年代中期,Java成为主流时,C ++是占主导地位的语言,而Web仍然是相当新的。而且,JVM和GC是主流开发中相对较新的概念。早期的JVM有点慢(与在裸机上运行的C ++相比),并且有时还会出现较长的垃圾收集暂停,这导致Java的声誉很慢。


这是由于GC背后的技术吗?我知道他们有一些策略(例如对象的世代层)可以提高GC阶段的效率。当时的策略是什么?
Stefano Borini 2010年

1
IANA JVM专家,但是我认为当时有一种用于GC的单线程标记/清除算法,该算法要求整个JVM在执行GC时暂停。如今,并发标记/清除和JVM中还有许多其他性能增强。
刘坚

2
现代GC算法很好,但我认为最大的改进是JIT。
Pascal Thivent

1

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

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


您认为高内存消耗是来自于该工具还是来自Java库?
Stefano Borini'2

就Eclipse而言-来自Eclipse基础架构本身。过去与“大量” GUI相同(我记得是JBuilder)。我有一种直觉,这是因为使用静态类型的语言来使用插件体系结构(如Eclipse)需要大量样板对象。Emacs也具有插件,并且在进行典型编码时其内存消耗比Eclipse少10-20倍。Emacs Lisp代码被编译为字节码并加载到emacs实例中,然后运行-类似于Java类加载器。我猜在Java中有大量实例化的中间对象可以允许某些可插入性。
Wojciech Kaczmarek

1

Java应用程序的主要问题是,由于库存运行时库很大,所以它很大。巨大的程序会占用大量内存,并且倾向于交换,这意味着它们会变慢。

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

您可能需要查看jamvm虚拟机,它是一个相当快速的解释器(没有本机代码),并且非常小。它甚至可以快速启动。


1

正如Pascal所说,Java与其他高级语言相当。但是,作为在Windows 98上使用原始JVM的人,我们可以说,当时Java虚拟机提供的抽象级别很痛苦。

基本上,这是我们今天在JVM中认为很少或没有优化的软件仿真。


0

人们通常会轻描淡写“它的解释”。因为从前,这种做法是很糟糕的,而那些以“太慢”而放弃Java却从不回去测试新版本的人会给他们带来不好的印象。

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


0

我认为有一天,也许不是在不久的将来,由于JIT编译器会大量使用运行时,因此JIT编译的语言在任何方面都将胜过编译的语言(嗯,也许不是启动时间/内存消耗)。行为及其运行平台。


6
我认为您的意思是说JIT编译(未解释)的代码将胜过AoT代码。解释总是比运行编译后的代码慢。这就是使用JIT编译器的原因。问题是:提前编译器和JIT编译器在输出方面几乎没有区别,只是JIT编译器必须更快地编译,并且可以使用运行时信息来暗示其优化。具有平台特定优化功能的特定于平台的AoT编译器几乎总是会击败JIT,因为对它们花费在优化上的时间没有限制。
BobMcGee 2010年

感谢您的回答,不要想像JIT编译器可以使用的时间很少。
helpermethod 2010年

您是说热点自适应优化之类的东西?
Stefano Borini,2010年

2
@BobMcGee:非常正确。可以将C ++程序构建为缓慢运行,并对其所有操作进行配置文件反馈。然后,编译器可以使用半小时的CPU时间和2 GB的RAM来自由地重建非常快速的版本。执行此操作的JIT将使用户离开。
Zan Lynx

1
对于服务器等长期运行的应用程序,JIT编译时间可以忽略不计。与JIT相比,带有PGO的AOT受限制的原因至少有两个。首先,大多数性能差异是通过轻量级优化实现的。比较gcc -O2和gcc -O3。大多数时候没有差异,有时-O3会稍微好一些,有时会稍差一些,但是我从未经历过> 2倍的差异。其次,即使将AOT与PGO一起使用,您也只能猜测配置文件将在使用现场。猜错了,您远远落后于JIT。而且实际的配置文件可能与配置非常相关。
PiotrKołaczkowski15年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.