Java 因其速度慢而享有一定声誉。
- Java真的很慢吗?
- 如果是,为什么?瓶颈在哪里?是因为JVM效率低下吗?垃圾收集?纯字节码库而不是JNI包装的C代码?许多其他语言都具有这些功能,但是它们并没有因速度慢而享有盛誉。
Java 因其速度慢而享有一定声誉。
Answers:
现代Java是最快的语言之一,即使它仍然是内存消耗大的人。Java的了,因为它曾经花费很长的时间VM启动正在缓慢的声誉。
如果您仍然认为Java运行缓慢,请参见基准测试结果。用预先编译的语言(C,Fortran等)编写的经过严格优化的代码可以胜过它;但是,Java的速度可以是PHP,Ruby,Python等的10倍以上。在某些方面,它可以击败常见的编译语言(如果它们使用标准库)。
现在没有“慢” Java应用程序的借口。归咎于开发人员和遗留代码/库,而不仅仅是语言。另外,也要怪任何“企业”。
库的编写通常是出于“正确性”和可读性,而不是性能。在我看来,这是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被设计为以牺牲一些性能为代价提供安全性和可移植性,并且表现出某些真正苛刻的操作。其缓慢的大多数声誉不再应有。
内存分配和取消分配既快速又便宜。我见过这样的情况:分配新的多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通过这种方式提供了一些非常有效的循环转换。
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.
没有任何在此链接的证据支持的野蛮主张。
最初,Java并不是特别快,但是也不是太慢。这些天来,Java非常快。从我刚才谈到的人那里,人们对Java缓慢的印象来自两点:
虚拟机启动时间慢。与本机应用程序相比,早期的Java实现花费很长时间来启动和加载需求库和应用程序。
慢的用户界面。早期的摇摆很慢。大多数Windows用户也很难找到默认的Metal L&F,这可能也无济于事。
考虑到以上几点,难怪人们会收到“ Java速度慢”的印象。
对于习惯于开发本机应用程序甚至Visual Basic应用程序的用户或开发人员,这两点是应用程序中最明显的东西,这是您对应用程序的第一印象(除非它是非GUI应用程序,仅适用于1.)。
当应用程序花8秒钟启动而不是立即启动的旧Visual Basic应用程序时,即使代码执行和启动时间可能根本没有连接,您也不会说服用户“它执行代码非常快”。
破坏第一印象是开始谣言和神话的好方法。谣言和神话很难消除。
简而言之,Java并不慢。人们对Java的态度是“慢”,这是基于10多年前对Java的第一印象。
阅读完充满评论的页面后说Java并不慢,我只需要以不同的观点回答即可。
语言的慢速很大程度上取决于您对“快速”的期望。如果您认为C#很快,那么Java当然也很快。如果您的问题域与数据库或半实时处理有关,那么Java当然也足够快。如果您愿意通过添加更多硬件来扩展应用程序,则Java可能对您来说很快。如果您认为5到10的常数因子加速是不值得的,那么您可能会认为Java快速。
如果您在大型数据集上进行数值计算,或者绑定到执行环境,在该环境中CPU资源是有限的,那么5-10的规模的持续加速将是巨大的。即使速度提高0.5,也可能减少500小时才能完成计算。在这些情况下,Java只是不允许您获得最后的性能,您可能会认为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启动,有一个容易察觉的暂停。即使是在紧密循环上运行得慢得多的纯解释器,对于这样的代码,这样的解释器仍常常显得更快,这仅仅是因为它可以被加载并可以更快地开始执行。
“长时间启动”的主要原因是动态链接。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快三倍。
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)。
对于大多数人而言,与Java交互的速度很慢。我们都已经看到咖啡杯在小程序出现之前在浏览器中旋转。启动JVM和下载applet二进制文件需要花费一些时间,这以一种值得注意的方式影响了用户体验。
Java咖啡杯明显标记了缓慢的JVM旋转和applet下载时间,这无济于事,因此人们将等待与Java关联。当Flash需要很长时间才能加载时,Flash开发人员会指定“正在加载”消息的商标,因此人们不会将Flash技术作为一个整体。
所有这些都与服务器上Java的性能或浏览器之外使用Java的许多其他方式无关。但这就是人们所看到的,以及非Java开发人员在考虑Java时会记住的内容。
Java之所以被称为慢是因为它很慢。Java的第一个版本没有“准时制”编译,甚至没有。这意味着该代码尽管是字节码,但仍在被解释,因此即使对于最简单的操作(如加两个整数),机器也必须进行各种比较,指针取消引用和函数调用。JIT编译器一直在不断改进;现在,如果我不小心编写C ++代码和不小心编写Java代码,Java有时会胜过 C ++,因为JIT编译器意识到我有一些不必要的指针反引用,并且会为我处理。
如果您想了解JIT编译的差异有多大,请在Computer Languages Benchmark Game上查看解释基准和未解释基准。(Pidigits使用外部库进行所有计算,因此基准不会改变;其他显示6-16倍的加速!)
所以,这就是主要原因。还有其他许多次要的问题也无济于事:最初,Java启动时间很长(现已确定);用Java编写的Web应用程序需要花费很长时间才能下载(现在,在可广泛访问的宽带上,并且预计会有大片电影之类的东西,现在情况就不那么如此了);UI Swing并不是(现在也没有)考虑性能而编写的,因此它比例如C ++中的等效项要快得多。
过去,Java很慢。由于几代的性能增强,它变得更快了。最后我听说,它通常在C#速度的10%以内-有时更快,有时更慢。
Java applet的启动仍然很慢,因为您必须启动整个JVM,该JVM必须加载所有类。有点像启动另一台计算机。JVM启动后,启动速度相当快,但是启动通常是人们记住的。
另外,至少有一些人永远不会相信Java的可行性。
斯特凡诺:
从一开始我就一直在使用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)到最大的服务器一起使用。
Java是一种高级语言,如今其声誉是要与其他可比较的高级语言相提并论。
它具有动态绑定语义。与将非虚拟方法编译为函数调用的C ++相比,即使世界上最好的Java编译器也必须生成效率较低的代码。但这也是一种更简洁,更高级的语义。
我不记得详细信息,但是在Java的早期,我听说每个Java对象都有一个互斥体,每种方法都需要获取并释放该互斥体。尽管不幸的是,每个对象只有一个互斥体并不能保护您免于竞争或死锁或并发程序中可能发生的任何不良影响,但这往往会使它更适合于并发。那部分,如果是真的,虽然有点天真,但这是出于善意。如果您对这方面有更多了解,请随时填写我的详细信息。
Java是高级语言的另一种方式是拥有Garbage-Collection。垃圾收集可能会慢malloc
而且free
对于分配一次他们需要的所有存储器和工作与程序。问题是,在没有垃圾回收的语言中,程序员往往只编写一次分配所有需要的内存的程序,如果发现某个最大大小常量已溢出,该程序将失败。因此,比较是苹果与橘子。当程序员作出努力与非GC语言链结构的动态分配编写和调试程序,它们有时会发现,他们的计划是不超过在GC语言更快,因为malloc
与free
不是免费的!他们也有开销。此外,没有GC会强制指定谁释放什么,而又必须指定谁释放什么,这有时会迫使您进行复制-当多个功能需要数据并且不清楚哪个将在最后使用它-而无需使用GC语言进行复制。
在90年代中期,Java成为主流时,C ++是占主导地位的语言,而Web仍然是相当新的。而且,JVM和GC是主流开发中相对较新的概念。早期的JVM有点慢(与在裸机上运行的C ++相比),并且有时还会出现较长的垃圾收集暂停,这导致Java的声誉很慢。
许多Java桌面应用程序(有时是Eclipse之类的东西)的GUI响应性很差,这可能是由于高内存消耗以及类加载器可以做很多IO的事实。情况正在改善,但几年前更糟。
许多(大多数)人喜欢做概括,所以说“ Java慢”是因为他们认为与应用交互时应用很慢。
Java应用程序的主要问题是,由于库存运行时库很大,所以它很大。巨大的程序会占用大量内存,并且倾向于交换,这意味着它们会变慢。
Sun JVM之所以大,是因为它有一个很好的字节码解释器,可以通过跟踪很多事情来工作。那意味着很多数据,这意味着内存。
您可能需要查看jamvm虚拟机,它是一个相当快速的解释器(没有本机代码),并且非常小。它甚至可以快速启动。
正如Pascal所说,Java与其他高级语言相当。但是,作为在Windows 98上使用原始JVM的人,我们可以说,当时Java虚拟机提供的抽象级别很痛苦。
基本上,这是我们今天在JVM中认为很少或没有优化的软件仿真。
我认为有一天,也许不是在不久的将来,由于JIT编译器会大量使用运行时,因此JIT编译的语言在任何方面都将胜过编译的语言(嗯,也许不是启动时间/内存消耗)。行为及其运行平台。