Java真的很慢吗?

2022-08-31 06:42:10

Java以速度慢而著称

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

答案 1

现代Java是最快的语言之一,尽管它仍然是一个内存占用。Java速度慢著称,因为过去需要很长时间才能启动VM。

如果您仍然认为Java很慢,请参阅基准测试游戏结果。用提前编译的语言(C,Fortran等)编写的严格优化的代码可以击败它;但是,Java的速度可以超过PHP,Ruby,Python等的10倍以上。在一些特定的领域,它可以击败常见的编译语言(如果它们使用标准库)。

现在没有借口“慢”Java应用程序。开发人员和遗留代码/库是罪魁祸首,远远超过语言。另外,责怪任何“企业”。

公平地说,对于“Java很慢”的人群,这里有一些地方它仍然很慢(2013年更新):

  • 编写库通常是为了“正确性”和可读性,而不是性能。在我看来,这是Java仍然声誉不佳的主要原因,尤其是服务器端。这使得字符串问题呈指数级恶化。一些简单的错误很常见:对象通常用于代替基元,从而降低性能并增加内存使用量。许多Java库(包括标准库)会经常创建字符串,而不是重用可变或更简单的格式(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而不是显式分配(这对许多小对象分配更友好)。人们可以编写C来击败这一点(通过滚动自定义内存管理和有效地执行malloc),但这并不容易。

  • 方法调用基本上是免费的,在某些情况下比大方法代码更快。HotSpot 编译器使用执行信息来优化方法调用,并具有非常有效的内联。通过使用额外的执行信息,它有时可以优于提前编译器,甚至(在极少数情况下)手动内联。与 C/C++相比,如果编译器决定不内联,则方法调用会降低一点性能。

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

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

  • 阵列拷贝经过高度优化。在最新版本中,Java使用手动调谐的汇编程序进行System.arraycopy。结果是,在数组复制/memcopy重度操作中,我看到我的代码以合理的边距击败了C中的等效代码。

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

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

  • 在JIT编译(Java 1.2 / 1.3)之前,该语言只是解释,而不是编译,因此非常慢。
  • JIT编译需要时间才能变得高效(每个版本都有重大改进)
  • 多年来,类加载已经变得更加高效。它曾经在启动期间效率低下且速度很慢。
  • Swing和UI代码没有很好地使用原生图形硬件。
  • 秋千太可怕了。我责怪AWT和Swing,为什么Java从未在桌面上流行起来。
  • 在库类中大量使用同步;现在提供不同步版本
  • 小程序需要永远加载,因为通过网络传输完整的 JAR 并加载 VM 以进行引导。
  • 用于严重性能损失的同步(每个 Java 版本都对此进行了优化)。不过,反射仍然是昂贵的。

答案 2

最初,Java并不是特别快,但它也不是太慢。如今,Java非常快。从我交谈过的人那里,Java缓慢的印象来自两件事:

  1. VM 启动时间慢。与本机应用程序相比,早期的Java实现需要很长时间才能启动和加载所需的库和应用程序。

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

鉴于上述几点,难怪人们会得到“Java很慢”的印象。

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

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

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

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


推荐