11 个简练的 Java 性能调优技巧

想要让你的项目一直高性能运作吗?以下有一些技巧你可以拿去消除缓存瓶颈,还有一些其他的性能调优建议。

大多数开发者认为性能优化是一个复杂的话题,它需要大量的工作经验和相关知识理论。好吧,这也不完全错。优化一个应用做到性能最优化可能不是件容易的任务,但是这并不意味着你没有相关的知识就什么也做不了。这里有一些易于遵循的建议和最佳实践可以帮助你创建一个性能良好的应用程序。

这些建议的大部分都是针对 Java 语言的。但是也有一些是跟语言无关的,你可以运用到任意的应用和程序中。在我们学习特定的 Java 编程性能调优之前,先来探讨一些通用的技巧。

  1. 在明确必要之前别急着优化

这可能是最重要的性能优化技巧之一。你应该遵循常见的最佳实践做法并在案例中高效地应用它。但是这并不意味在证明必要之前,你应该更换任何标准库或构建复杂的优化。

多数情况下,过早地优化会占用大量的时间,而且会使代码变得难以理解和阅读。更糟糕的是,这些优化通常并没带来任何好处,因为你花了大量的时间在优化应用中的非关键部分。

那么,要怎么证明东西需要优化呢?

首先,你需要定义你的代码速度得多快。例如,为所有 API 调用指定最大响应时间,或者指定在特定时间范围内要导入的记录数量。在做完这些后,你需要确定你应用中哪些部分太慢需要改进。当完成这些后,你就可以来看看第二个技巧提示。

  1. 使用分析器找到真正的瓶颈

在完成第一部分的优化建议以鉴别出你应用中需要提升的部分后,要从哪里入手呢?

你可以有两种途径来解决这个问题:

1)查看你的代码,从看起来可疑的或者你觉得可能会导致出现问题的地方入手

2)或者使用分析器获取代码每个部分的行为(执行过程)和性能的详细信息。

希望我不需要解释为什么应该始终遵循第二种途径/方法的原因。

很显然,基于分析器的方式可以让你更好地理解代码的性能影响,并允许你去专注于更关键的部分(代码)。即使你曾经使用过分析器,你一定记得你曾经多么惊讶于一下就找到了代码的哪些部分产生了性能问题。我第一次的猜测不止一次地导致我走错了方向。

  1. 为整个应用程序创建一个性能测试套件

这是另一个通用的可以帮助你避免在将性能改进部署到产品中之后经常会发生的许多意外问题的技巧。你应该总是定义一个性能测试套件来测试整个应用程序,并在性能改进之前和之后运行它。

这些额外的测试运行将帮助你识别你的改动所引起的功能和性能上的副作用,并确保不会导致弊大于利的更新。如果你处理的是被应用程序的多个不同部分使用的组件,如数据库或缓存,那这一点尤为重要。

  1. 优先关注最大瓶颈

在创建了测试套件并使用分析器分析你的应用程序之后,你可以列出一系列需要解决以提高性能的问题列表。这很好,但这并没有回答你需要从哪里开始的问题。你可以专注于速成方案,或从最重要的问题开始。

速成方案一开始可能会很有吸引力,因为你可以很快显示第一个成果。但有时,可能有必要说服其他团队成员或管理层认为性能分析是值得的。

一般来说,我建议从顶层开始,首先开始处理最重要的性能问题。这将为你提供最大的性能改进,而且你可能仅需要解决这些问题中的一小部分就能满足你的性能要求。

常见的通用调优技巧到此结束。接下来让我们仔细看看一些特定于 Java 的技巧。

  1. 使用 StringBuilder 以编程方式连接字符串

在 Java 中有很多不同的选项来连接字符串。例如,你可以使用简单的 + 或 + = ,以及老的 StringBuffer 或 StringBuilder 。

那么,你应该选择哪种方法呢?

答案取决于连接字符串的代码。如果你是以编程方式将新内容添加到字符串中,例如在 for 循环中,则应使用 StringBuilder 。它很易于使用,并提供比 StringBuffer 更好的性能。但请记住,与 StringBuffer 相比, StringBuilder 不是线程安全的,可能并不适用于所有情况。

你只需要实例化一个新的 StringBuilder 并调用 append 方法来向 String 中添加一个新的部分。在你添加完了所有的部分后,你可以调用 toString() 方法来检索已连接的字符串。

下面的代码片段展示了一个简单的例子。在每次迭代期间,该循环将 i 转换为一个 String ,并将其与空格一起添加到StringBuilder sb 中。所以,最后,这段代码在日志文件中写入 “This is a test0 1 2 3 4 5 6 7 8 9” 。

StringBuilder sb =newStringBuilder(“This is a test”);for(inti=0; i<10; i++) {

sb.append(i);

sb.append(” “);

}

log.info(sb.toString());

正如你在我们的公众号Java技术栈代码片段中看到的,我们可以为字符串的第一个元素提供到构造函数中。这会创建一个StringBuilder ,其中包含了你所提供的字符串以及 16 个额外字符的容量。当你向StringBuilder 中添加更多字符时,你的 JVM 将动态的增加StringBuilder 的大小。

如果你已经知道字符串将包含多少个字符,则可以将该数字提供给不同的构造方法以实例化具有指定容量的 StringBuilder 。这进一步提高了效率,因为它不需要动态扩展其容量。

  1. 使用 + 连接一个语句中的字符串

当你使用 Java 实现你的第一个应用程序时,可能有人告诉过你不要使用 + 来连接字符串。如果你是在应用程序逻辑内连接字符串的话,这是对的。字符串是不可变的,每个字符串的连接结果都被存储在一个新的字符串对象中。这需要额外的存储空间,并可能使你的应用程序运行缓慢,特别是当你在一个循环内连接多个字符串的情况下。

在这些情况下,你应该遵循技巧 5 中的内容,并使用StringBuilder 。

但如果你只是将字符串分成多行来改善代码的可读性,这并不适用。

Query q = em.createQuery(“SELECTa.id, a.firstName, a.lastName ”

  • “FROMAuthor a ”
  • “WHEREa.id = :id”);

在这些情景下,你应该使用简单的 + 来连接字符串。你的 Java 编译器会优化它,并在编译时完成连接。因此,在运行时,你的代码将只使用一个字符串,并不需要任何连接操作。

  1. 尽可能使用基本类型

避免任何开销并提高应用程序性能的另一种简便快速的方法是使用基本类型而不是其包装类。所以,最好使用 int 而不是 Integer ,是 double 而不是 Double 。这将使得你的 JVM 将值存储在堆栈而不是堆中,以减少内存消耗,并更有效地处理它。

  1. 尽量避免大整数和小数

由于我们已经在讨论数据类型,所以我们也应该快速浏览大整数和小数。尤其是后者因其精确性而受欢迎。但这是有代价的。

大整数和小数比一个简单的long型或double型需要更多的内存,并会显著减慢所有的运算。所以,如果你需要额外的精度,或者如果你的数字超出一个较长的范围,最好要三思。这可能是你需要更改并解决性能问题的唯一方法,尤其是在实现数学算法时。

  1. 优先检查当前日志级别

这个建议应该是显而易见的,但不幸的是,很多人在写代码的时候都会忽略它。 在创建调试消息之前,应该总是优先检查当前日志级别。 否则,你可能会创建一个附加你日志消息的字符串,而该字符串之后将被忽略。

这里有两个你不应该这样做的反面例子。

// don’t do this

log.debug(“User[” + userName + “]called method X with[” + i + “]”);

// or this

log.debug(String.format(“User[%s]called method X with[%d]”, userName,i));

在这两个示例中,你都将执行创建日志消息所有必需的步骤,而不知道日志框架是否将使用日志消息。 因此在创建调试消息之前,最好先检查当前的日志级别。

// do thisif (log.isDebugEnabled()) {

log.debug(“User[” + userName + “]called method X with[” + i + “]”);

}

  1. 使用 Apache Commons StringUtils.Replace 而不是 String.replace

一般来说,String.replace 方法可以正常工作,并且效率很高,尤其是在你使用 Java 9 的情况下。但是,如果你的应用程序需要大量的替换操作,并且没有更新到最新的 Java 版本,那么检查更快和更有效的替代品依然是有必要的。

有一种候选方案是 Apache Commons Lang 的StringUtils.replace 方法。正如 Lukas Eder 在他最近的一篇博客文章中所描述的,它远远胜过了 Java 8 的 String.replace 方法。

而且它只需要很小的改动。你只需要将 Apache Commons Lang 项目的 Maven 依赖项添加到你的应用程序的 pom.xml 中,并将 String.replacemethod 的所有调用替换为 StringUtils.replace 方法。

// replace this

test.replace(“test”, “simpletest”);

// with this

StringUtils.replace(test, “test”, “simpletest”);

11.昂贵的缓存资源,如数据库连接

缓存是避免重复执行昂贵或常用代码片段的流行解决方案。总的思路很简单:重复使用这些资源比创建一个新的资源更划算。

一个典型的例子是缓存池中的数据库连接。新连接的创建需要时间,如果你重用现有连接,则可以避免这种情况。

你也可以在 Java 语言源码中找到其他的例子。例如,在 Integer 类中的valueOf方法缓存了介于 -128 到 127 之间的值。你可能会说创建一个新的 Integer 并不是太昂贵,但是由于它经常被使用,因此缓存最常用的值也可以×××能优势。

但是,当你考虑使用缓存时,请记住缓存实现也会产生开销。你需要花费额外的内存来储存可重复使用的资源,因此你可能需要管理你的缓存以使资源可访问,并删除过期的资源。

所以,在开始缓存任何资源之前,请确保它们是经常使用的,以超过缓存实现的开销(代价)。

总结

正如你所看到的,有时不需要太多的工作就可以提高你的应用程序的性能。本文中的大部分建议只需要稍作努力就可以将它们应用于你的代码中。

但还是那句话,最重要的还是那些与是什么编程语言无关的技巧:

在你知道其必要性之前不要进行优化

使用分析器(profiler)来查找真正的瓶颈

优先处理最大的瓶颈

1、具有1-5工作经验的,面对目前流行的技术不知从何下手,需要突破技术瓶颈的可以加群。

2、在公司待久了,过得很安逸,但跳槽时面试碰壁。需要在短时间内进修、跳槽拿高薪的可以加群。

3、如果没有工作经验,但基础非常扎实,对java工作机制,常用设计思想,常用java开发框架掌握熟练的,可以加群。

4、觉得自己很牛B,一般需求都能搞定。但是所学的知识点没有系统化,很难在技术领域继续突破的可以加群。

5.群号 744677563

6.阿里Java高级大牛直播讲解知识点,分享知识,知识点都是各位老师多年工作经验的梳理和总结,带着大家全面、科学地建立自己的技术体系和技术认知!

原文地址:http://blog.51cto.com/13732225/2121556

时间: 2024-10-28 14:47:22

11 个简练的 Java 性能调优技巧的相关文章

11 个简单的 Java 性能调优技巧

大多数开发人员理所当然地以为性能优化很复杂,需要大量的经验和知识.好吧,不能说这是完全错误的.优化应用程序以获得最佳性能不是一件容易的事情.但是,这并不意味着如果你不具备这些知识,就不能做任何事情.这里有11个易于遵循的建议和最佳实践可以帮助你创建一个性能良好的应用程序. 大部分建议是针对Java的.但也有若干建议是与语言无关的,可以应用于所有应用程序和编程语言.在讨论专门针对Java的性能调优技巧之前,让我们先来看看通用技巧. 1.在你知道必要之前不要优化 这可能是最重要的性能调整技巧之一.你

Java性能调优11个实用技巧

1.在必要之前,先不要优化 这可能是最最重要的性能调优技巧之一.你应该遵循常见的最佳实践,并尝试有效地实现你的用例.但这并不意味着在证明它是必要之前,替换任何标准库或构建复杂的优化. 在大多数情况下,过早的优化占用了大量的时间,使得代码难以读取和维护.更糟糕的是,这些优化通常不会带来任何好处,因为你花费了大量时间来优化应用程序的非关键部分. 那么,你如何证明你需要优化某些东西呢? 首先,你需要确定应用程序代码的速度,例如,为所有API调用指定一个最大响应时间,或者指定在特定时间范围内导入的记录数

Java性能调优笔记

Java性能调优笔记 调优步骤:衡量系统现状.设定调优目标.寻找性能瓶颈.性能调优.衡量是否到达目标(如果未到达目标,需重新寻找性能瓶颈).性能调优结束. 寻找性能瓶颈 性能瓶颈的表象:资源消耗过多.外部处理系统的性能不足.资源消耗不多但程序的响应速度却仍达不到要求. 资源消耗:CPU.文件IO.网络IO.内存. 外部处理系统的性能不足:所调用的其他系统提供的功能或数据库操作的响应速度不够. 资源消耗不多但程序的响应速度却仍达不到要求:程序代码运行效率不够高.未充分使用资源.程序结构不合理. C

JAVA性能调优-在循环条件中不要使用表达式

1.JAVA性能调优-在循环条件中不要使用表达式 我们在学习JAVA性能调优的时候,经常能看到这一的一段话:在不做编译优化的情况下,在循环中,循环条件会被反复计算,如果不使用复杂表达式,而使循环条件值不变的话,程序将会运行的更快. import java.util.vector; class cel { void method(vector vector) { for (int i= 0; i < vector.size (); i++)  //violation ; //... } } 更正:

java 性能调优工具

1.jstack 用法jstack [option] pid -l long listings,会打印出额外的锁信息,在发生死锁时可以用jstack -l pid来观察锁持有情况 -m mixed mode,不仅会输出Java堆栈信息,还会输出C/C++堆栈信息(比如Native方法) 找出进程内最耗费CPU的线程,可以使用ps -Lfp pid或者ps -mp pid -o THREAD, tid, time或者top -Hp pid printf "%x\n" pid 得到pid的

java 性能调优和GC

JAVA 性能调优和GC http://blog.csdn.net/gzh0222/article/details/7663181 JAVA GC调优手记 http://blog.csdn.net/firecoder/article/details/7225654 JAVA GC 日志详解 http://blog.csdn.net/alivetime/article/details/6895537 JAVA 内存参数设置 http://heipark.iteye.com/blog/1356113

Java性能调优_深入Java程序性能调优(并行开发、JVM调优)

深入Java程序性能调优(阿姆达尔定律.缓存组件.并行开发.线程池.JVM调优)课程讲师:special课程分类:Java核心适合人群:初级课时数量:33课时更新程度:完成用到技术:阿姆达尔定律.缓存组件.并行开发.线程池.JVM调优涉及项目:模式在实际开发中运用深入Java程序性能调优下载: http://pan.baidu.com/s/1ntn0ZTB 密码: ijluJava性能调优:国内关于Java性能调优的课程非常少,如此全面深入介绍Java性能调优,北风算是独家,Special讲师,

JAVA性能调优- try/catch块和循环

1.JAVA性能调优-将try/catch块移出循环 据说把try/catch块放入循环体内,会极大的影响性能.因为使用了try/catch模块的使用,会让JAVA虚拟机做很多额外的工作.就好比对每个人说,"嗨,哥们,路上可能有蛇.于是听到的人只好手拿木棍,小心翼翼的往前走". 把try/catch块放到循环外面,就好比对一大群人说,"嗨,兄弟们,路上可能有蛇.于是听到的人安排部分人员拿木棍往前走,其他人基本不受影响" 这个理论蛮不错的,测试下对性能的实际影响 2.

推荐书籍:《Java性能调优指南》

本书作者是Java性能和Java HotSpot 虚拟机领域的佼佼者,帮助你利用现代软工实践提高性实战生涯中总结能,避免常见错误,从技巧和窍门. 利用G1克服并行.串行和CMS垃圾收集器的局限性了解G1  GC收集的各个阶段,包括年轻代和老年代在G1的引擎下微调您的应用程序确定潜在优化方案,解释实验结果,并付诸行动探索的HotSpot虚拟机内部使用热点VM服务代理分析.分流,并解决不同的热点 <Java性能调优指南>主要展示了如何在当今先进的多核硬件和复杂的操作系统环境下,系统且主动地提高Ja