Java性能

时间:2020-01-09 14:11:12  来源:igfitidea点击:

Java性能调优在某种程度上是种黑艺术的。很难找到有关Java性能调优的良好信息,并且有很多原因。

首先,性能调整在很大程度上取决于我们所构建的系统和系统所运行的硬件。随着时间的流逝,Java虚拟机和执行系统的硬件在不断发展。随着这种发展,适用的Java性能技术也发生了发展。

其次,我们的Java开发人员饱受关于Java编译器和Java虚拟机的许多不真实的故事的困扰。人们常说Java编译器或者VM可以比我们做的更好地优化代码。

但是,这并不总是完全正确的。算法,数据格式,数据结构,内存使用模式,IO使用模式等都很重要!在许多情况下,我们可以比Java编译器和JVM更好地优化代码,因为与Java相比,我们更了解系统正在尝试执行的操作,其数据结构,数据使用模式等。

请注意:此Java性能教程是一个多页教程。本页面仅作介绍!

主要调优技巧

Java开发中有许多不同的性能优化技巧,但它们都倾向于属于以下类别之一:

  • 减少执行任务所需的工作(操作)。
  • 将代码与硬件(CPU,RAM,SSD等)对齐(又称机械同情)
  • 在可能的情况下,尽可能地使任务并行化。

减少执行给定任务所需的工作(操作)需要我们提出一种更快的方法来执行该任务。有时,它还需要有关Java内幕到底发生了什么,以及一直到硬件层的知识。有时,我们可以提出更紧凑的数据结构,更快的数据结构或者更快的算法等,从而可以加快手头的任务。

使代码与基础硬件的工作方式对齐包括一些技巧,例如在8个字节的地址(0、8、16等)上对齐变量,或者将数据保留在同一缓存页中,确保数据彼此靠近存储以利用串行内存访问,或者减少分支以改善/删除分支预测(以避免CPU管道刷新),或者了解SSD的缓存大小等。

减少CPU与数据之间的距离是使代码和数据与底层硬件的工作方式保持一致的一个典型示例。缩短CPU与它所处理的数据之间的距离通常可以加快数据的处理速度。访问CPU寄存器内部的数据的速度比L1缓存中的数据快,后者比L2缓存中的数据快,后者比L3缓存中的数据快,它比主RAM快,后者比磁盘快,而磁盘通常比远程计算机快。

将任务分解为可以并行执行的较小任务,或者简单地并行执行多个独立任务也是在某些情况下可以显着提高性能的一项技术。现代CPU趋向于获得越来越多的并行执行单元(内核),因此当可以通过简单的方式分解任务或者它们已经彼此独立时,并行化可以极大地提高性能。并行化也可以实现为多台计算机协同工作以解决问题,而不是一台计算机。

影响性能的因素

任何系统都有一些重复出现的方面会影响其性能。这些方面是:

  • 内存管理
  • 数据结构
  • 演算法
  • 并发
  • 网络通讯
  • 可扩展性

内存管理,数据结构和算法通常紧密地链接在一起。某种算法可能需要某种数据结构。某种数据结构可能会影响内存管理。

并发意味着系统可以很好地将负载分布在多个线程和CPU上。并发也可以链接到数据结构,但不总是如此。这取决于我们系统的并发模型。

网络通信也可能会影响系统的性能。某些网络协议比其他网络协议要快,我们有时可以为自己的特定用例创建更快的自定义网络协议。此外,系统的通信模式不仅会影响消息的来回传输方式,而且会影响通信的频率,以及通信是同步还是异步,从而影响性能。

系统的可伸缩性意味着在扩展或者扩展硬件时其性能如何。向上扩展(垂直扩展)意味着购买一台更大的计算机,该计算机具有更多的内存,更多的CPU,更快的磁盘,NIC等。向外扩展(水平扩展)意味着将系统分布在多台计算机上。

可重用的Java性能原则

尽管针对每个单独的应用程序进行了大量性能优化,但仍有Java性能原理,技术和模式可在许多不同类型的应用程序和情况之间重用。本Java性能教程将主要关注此类可重用的原理。

我也可能会不时地深入研究特定的系统/用例,以说明如何优化该系统。这样的示例案例可能非常具有启发性,尽管在涉及到可以被认为具有竞争优势(并且表现出色)的事物时,许多公司倾向于将自己的牌贴近身体。

Java核心性能原则

本教程中的技巧基于的Java性能调整的最常见核心原则是:

  • 内存比磁盘快-快得多-并且内存便宜。
  • 顺序读取或者写入时,所有存储(内存/磁盘)工作最快。任意访问速度较慢。
  • 对象分配和垃圾回收很慢。
  • 数据格式和数据结构在速度上有很大的不同。
  • 异步IO的伸缩性优于同步IO。
  • 单线程性能是多线程性能的前提。
  • 共享内存(或者磁盘)并发性很差,因为它通常在系统繁忙时导致大量争用。

我们可能会注意到,本教程中的许多性能提示都基于这些相同的原理。

关于单线程性能的最后一个可能使某些人感到惊讶。并行计算和并行编程如今(2014年)风行一时,因此我们可能已经被告知,我们应该考虑将问题分解为可以并行解决的较小问题。不幸的是,没有那么多问题可以轻易并行化。

此外,如果服务器同时处理许多任务(例如传入的HTTP请求),则服务器中的其他CPU可能已经在忙于处理自己的任务。并行任务对我们毫无帮助,因为CPU已经很忙。实际上,这可能会损害性能(除非我们拥有的CPU比平均使用的CPU多)。

Java Performance Toolkit和基准

该Java性能教程中介绍的代码和基准将在将来的某个时候在GitHub上提供。这些代码和基准将存在于单独的GitHub存储库中。

Java性能工具包主要用于显示本教程中介绍的思想的实现。它们可能并不总是具有准备在实际应用中使用的全函数,但有时可能仅用作某些想法的概念证明。但是,如果需要,请随时在应用程序中使用该工具包。

Java性能基准旨在在我们自己的硬件上运行,因此我们可以查看给定的技术,实现等如何在特定硬件上运行。