凡事预则立,不预则废,和很多事情一样。Java性能调优的成功。离不开行动计划、方法或策略以及特定的领域背景知识。为了在Java性能调优工作中有所成就。你得超越“花似雾中看”的状态,进入“悠然见南山”或者已然是“一览众山小”的境地。

这三个境地的说法可能让你有些糊涂吧。以下进一步解释。

  • 花似雾中看(I don't know what I don't know)。

    有时候下达的任务会涉及你所不熟悉的问题域。理解陌生问题域首先面临的困难就是怎样竭尽所能地学会它,由于你对它差点儿一无所知。对于这类问题域。你有很多东西不了解,或者不知道重点。

    换句话说,这个问题域有哪些东西须要了解,你还傻傻看不清楚。这个阶段就是“花似雾中看”。

  • 悠然见南山(I know what I don't know)。刚进入不熟悉的问题域时,你对它知之甚少,随着时间的推移,你对它的很多重要方面都已有所认识,仅仅是对重要的详细细节还缺乏了解。这时。你能够算是刚刚“见南山”。
  • 一览众山小(I already know what I need to know)。

    还有些时候,你对任务的问题域很熟悉。或者已经具有该领域所必备的技能和知识,是这方面的专家。或者你对问题域足够了解,处理起来得心应手。比方你已经掌握了必要的知识,解决问题游刃有余。假设达到这个境地。那就意味着你已经是“一览众山小”了。

通常觉得,传统的软件开发过程主要包含4个阶段:分析、设计、编码和測试。如图1-1所看到的。

图1-1 传统软件开发过程

替换图字: start:開始; analysis:分析; design:设计; code:编码; test:測试;
quality:质量合格?; yes:是; no:否; deploy:部署

分析是开发过程的第一步,用于评估需求、权衡各种架构的利弊以及构思高层抽象。设计则根据分析阶段的基本架构和高层抽象,进行更精细的抽象并着手考虑详细实现。编码自然就是设计的实现。编码之后是測试。用以验证实现是否合乎应用需求。

值得注意的是。測试阶段通常仅仅包含功能測试。即检验应用的运行是否合乎需求规格。一旦測试完毕。应用就能够公布给客户了。

遵循这样的传统软件开发过程的应用。通常要到測试或即将公布时才会关注性能或扩展性。

为了解决问题。Wilson和Kesselman对传统软件开发过程做了些补充,在传统开发模型基础上引入了性能測试分析阶段。參见他们的畅销书Java Platform Performance

他们建议在測试阶段之后添加性能測试。并将“性能測试是否通过”设定为产品是否公布的标准。假设达到性能和扩展性标准,应用就能够公布,否则就要转向性能分析。并根据分析结果回到之前的某个或者某些步骤。换句话说,通过性能分析来定位性能问题。Wilson和Kesselman加入的性能測试分析如图1-2所看到的。

图1-2 Wilson和Kesselman加入性能測试分析之后的软件开发过程

替换图字: start:開始; analysis:分析; design:设计; code:编码; performance test:性能測试; performance acceptable:性能測试是否通过; profile:性能分析; yes:是; no:否; deploy:部署

对分析阶段提炼出来的性能需求,Wilson和Kesselman建议以用例(use case)的方式特别标识出来,这有助于在分析阶段制定性能评估指标。只是应用的需求文档中通常都不会明白描写叙述性能或扩展性需求。假设你正在开发的应用还没有明白定义这些需求。那就应该想办法将它们挖掘出来。

拿吞吐量和延迟性需求举例。以下清单列举了挖掘这些需求所要考虑的问题。

  • 应用预期的吞吐量是多少?
  • 请求和响应之间的延迟预期是多少?
  • 应用支持多少并发用户或者并发任务?
  • 当并发用户数或并发任务数达到最大时,可接受的吞吐量和延迟是多少?
  • 最差情况下的延迟是多少?
  • 要使垃圾收集引入的延迟在可容忍范围之内,垃圾收集的频率应该是多少?

需求和相应的用例文档应该回答上述问题,并以此制定基准測试和性能測试,确保应用能够满足性能和扩展性需求。基准測试和性能測试应该在性能測试阶段运行。评估用例时有些用例的风险过高,难以实现,应该在分析阶段后期。通过一些原型、基准測试和微基准測试来减少此类风险。分析结束后再变更决策的代价很高,这种方法能够让你事先对决策进行评估。

软件开发周期中的软件缺陷、低劣设计和糟糕实现发现得越晚,修复的代价就越大,这是一条颠扑不破的金科玉律。减少用例的高风险有助于避免这些代价昂贵的错误。

如今很多应用在开发过程中都会使用自己主动构建和測试。Wilson和Kesselman建议改进软件开发过程。在自己主动构建或測试中进一步加入自己主动性能測试。

自己主动性能測试能够发出通知,比方用电子邮件将性能測试结果(如性能是衰减还是改善,或性能指标的达成度)发送给干系人。这个过程能够将因不满足应用性能指标而失败的測试,以及測试的统计数据自己主动记录到追踪系统。

将性能測试集成到自己主动构建过程中后。每次代码变更提交到源码库时。都能很easy地追踪因变更而导致的性能变化,也就能在软件开发的早期发现性能衰减。

另外。将统计方法和自己主动统计分析加入到自己主动性能測试系统中也值得考虑。运用统计方法能够进一步验证性能測试的结果。

自顶向下和自底向上是两种经常使用的性能分析方法。

顾名思义,自顶向下(Top Down)着眼于应用顶层,从上往下寻找软件栈中的优化机会和问题。相反,自底向上(Bottom
Up)则从软件栈最底层的CPU统计数据(比如CPU缓存未命中率、CPU指令效率)開始,逐渐上升到应用自身的结构或该应用常见的使用方式。应用开发者经常使用自顶向下的方法。而性能问题专家则通常採用自底向上的方法,用以辨别因不同硬件架构、操作系统或不同的Java虚拟机实现所导致的性能差异。如你所想。不同方法能够用来查找不同类型的性能问题。

自顶向下大概是最经常使用的性能调优方法。假设须要更改应用软件栈的顶层代码进行调优,这也是最经常使用的方法。

使用自顶向下的方法时。通常你须要从干系人发现性能问题的负载開始监控应用。应用的配置变化或日常负荷变化可能导致性能减少,这样的情况下。须要持续地监控应用。此外,当应用的性能和扩展性需求发生变化时,应用可能无法满足新的要求。这时也须要监控应用程序的性能。

无论何种原因引起的性能调优。自顶向下的第一步总是对运行在特定负载之下的应用进行监控。监控的范围包含操作系统、Java虚拟机、Java EE容器以及应用的性能測量统计指标。基于监控信息所给出的提示再开展下一步工作,比如JVM垃圾收集器调优、JVM命令行參数调优、操作系统调优,或者应用程序性能分析。

性能分析可能导致应用程序的更改,或者发现第三方库或Java SE类库在实现上的不足。

在不同平台(指底层的CPU架构和数量不同)上进行应用性能调优时。性能专家常使用自底向上的方法。

将应用迁移到其它操作系统上时,也经常使用这样的方法改善性能。在无法更改应用源码时,比如应用已经部署在生产环境中,或者系统供应商为了在竞争中占得先机而必须将性能发挥到极致,也经常会使用这样的方法。

自底向上须要收集和监控最底层CPU的性能统计数据。

监控的CPU统计数据包含运行特定任务所须要的CPU指令数(通常称为路径长度,path length),以及应用在一定负载下运行时的CPU缓存未命中率。尽管还有其它重要的CPU统计数据,但这两项是自底向上中最经常使用的。在一定负载下,应用运行和扩展所需的CPU指令越少。运行得就越快。

减少CPU缓存未命中率也能改善应用的性能,由于CPU缓存失效会导致CPU为了等待从内存获取数据而浪费若干个周期,而减少CPU缓存未命中率,意味着CPU能够减少等待内存数据的时间,应用也就能运行得更快。

自底向上关注的一般是在不更改应用的前提下。改善CPU使用率。假如应用能够更改。自底向上也能为怎样改动应用提供建议。这些更改包含应用源码的变动。如将经常使用的数据移到一起,使得訪问同一条CPU缓存行(CPU cache line)就能获取这些数据,而不用等待从内存中获取数据。

这个改动能够减少CPU缓存未命中率。从而减少CPU等待内存数据的时间。

现代Java虚拟机集成了成熟的JIT编译器,能够在Java应用的运行过程中进行优化,比方根据应用的内存訪问模式或应用特定的代码路径。生成更有效的机器码。也能够调整操作系统的设置来改善性能,比如更改CPU调度算法。或者改动操作系统的等待时间(指操作系统在将应用运行线程迁移到其它CPU硬件线程之前所等待的时间)。

假设你觉得能够用自底向上的方法,那应该先从收集操作系统和JVM的统计数据開始。监控这些统计数据能够为下一步应该关注哪些重点提供线索。

本文内容摘自《Java性能优化权威指南》

Java SE和Java EE应用的性能调优的更多相关文章

  1. Java生鲜电商平台-API请求性能调优与性能监控

    Java生鲜电商平台-API请求性能调优与性能监控 背景 在做性能分析时,API的执行时间是一个显著的指标,这里使用SpringBoot AOP的方式,通过对接口添加简单注解的方式来打印API的执行时 ...

  2. Java SE、Java EE、Java ME

    Java SE(Java Platform,Standard Edition).Java SE 以前称为 J2SE.它允许开发和部署在桌面.服务器.嵌入式环境和实时环境中使用的 Java 应用程序.J ...

  3. Java SE、Java EE和Java ME有什么区别?

    Java现在已不仅仅是一种语言,从广义上说,它代表了一个技术体系.该体系根据应用方向的不同主要分为Java SE.Java EE和Java ME的3个部分. 1998年12月份Sun公司公布的Java ...

  4. java的几个版本以及jre,jdk等概念——【转载】JDK、Java SE、Java EE、Java ME我该选

    我们平时使用的一些软件,有一部分需要Java环境的支持,但是SUN那么多的产品,让人眼花缭乱的版本号,前看后看都差不多的缩写,让我们选择起来的时候常常望而却步,只好跟着感觉走.所以下面我要介绍的就是那 ...

  5. 浅谈Java SE、Java EE、Java ME三者的区别

    本文把JAVA SE.JAVA EE.JAVA ME拿来做下区别,同时也分享一下作者的一些成果.目前的Java平台根据软件开发人员.服务提供商和设备生产商可以针对特定的市场可以分为三个版本JAVA S ...

  6. Java SE、Java EE、Java ME 三者区别

    现在一个个来分析 1. Java SE(Java Platform,Standard Edition).Java SE 以前称为 J2SE.它允许开发和部署在桌面.服务器.嵌入式环境和实时环境中使用的 ...

  7. Java、Java SE、Java Web和Java EE的区别

    刚接触Java对这些概念上的东西有点模糊,查了很多资料,想把它分享出来,要是哪里不对请大家指正(^_^) 1.Java 毫无疑问这就是门语言和C.C++.C#一样没什么好说的. 2.Java SE和J ...

  8. 24. Java SE 、 Java EE 、JavaME 、 JavaWeb 直接的区别和联系

    这个是在别人博客抄的,并不是本人撰写 Java是一门编程语言.Java分为三大版本,SE即标准版,包含了Java核心类库,主要用来开发桌面应用:EE即企业版,包含SE,又有扩展部分(Servlet,J ...

  9. Java SE、Java EE、Java ME三者的区别

    1. Java SE(Java Platform,Standard Edition).Java SE 以前称为 J2SE.它允许开发和部署在桌面.服务器.嵌入式环境和实时环境中使用的 Java 应用程 ...

随机推荐

  1. 软工网络16个人作业2——WordCount

    Deadline: 2018-9-17 22:00PM,以博客提交至班级博客时间为准 要求参考来自:https://www.cnblogs.com/xinz/archive/2011/11/27/22 ...

  2. OpenCV设置保存图像压缩率

    OpenCV写入静态图片时,imwrite函数第三个参数可以设置压缩率,默认值为95. cv::Mat inImage= cv::imread("lena.jpg"); vecto ...

  3. python中逻辑运算符“+”的特殊之处

    num = num + num 与 num += num 的区别(其他语言中这两种方式可以划等号,但是python中不可以): num = num + num: num = [100] def tes ...

  4. [转]微擎MVC

    本文转自:https://www.kancloud.cn/donknap/we7/134626 控制器 控制器以文件夹.文件的形式组织,位于系统的 source 目录下,每一个目录代表一个 contr ...

  5. MyBatis(国税)

    一.MyBatis概要 1.1.ORM介绍 对象关系映射(Object Relational Mapping,简称ORM,或O/RM,或O/R mapping),用于实现面向对象编程语言里不同类型系统 ...

  6. 作用域public、private、protected、以及不写时的区别?

    区别如下: 作用域 当前类 同包 子孙类 其他 public     √ √ √ √ protected   √ √ √ X default    √  √ X X private    √  X X ...

  7. Java8的lambda表达式和Stream API

    一直在用JDK8 ,却从未用过Stream,为了对数组或集合进行一些排序.过滤或数据处理,只会写for循环或者foreach,这就是我曾经的一个写照. 刚开始写写是打基础,但写的多了,各种乏味,非过来 ...

  8. Confluence设置MySQL数据库报错:必须使用'READ-COMMITTED'作为默认隔离级别。

    解决方案: mysql -u root -p123456 SET GLOBAL tx_isolation='READ-COMMITTED'; mysql数据库创建 1.设置mysql隔离级别 SET ...

  9. Change事件多参

    @change="(value) => selected(value, item)" selected(val, item) { if (val === true) { th ...

  10. 2018-01-04 浅尝The Little Prover一书, 重逢Chez Scheme

    书开篇之前说, 本书的目标的一个例子: 证明(reverse (reverse x))对于任何列表x, 结果总是x. (安装Chez Scheme的200字请看最后) 书刚开始, 就用到一个schem ...