Java SE和Java EE应用的性能调优

凡事预则立,不预则废,和许多事情一样,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建议改进软件开发过程,在自动构建或测试中进一步添加自动性能测试。自动性能测试可以发出通知,比如用电子邮件将性能测试结果(如性能是衰减还是改善,或性能指标的达成度)发送给干系人。这个过程可以将因不满足应用性能指标而失败的测试,以及测试的统计数据自动记录到追踪系统。

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

另外,将统计方法和自动统计分析添加到自动性能测试系统中也值得考虑。运用统计方法可以进一步验证性能测试的结果。

自顶向下和自底向上是两种常用的性能分析方法。顾名思义,自顶向下(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应用的性能调优

时间: 2024-10-16 05:55:52

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

Java--- J2EE、Java SE、Java EE、Java ME 区别

java SE=Java Standard EditionJava EE=Java Enterprise EditionJava ME=Java Mobile Edition SE主要用于桌面程序,控制台开发(JFC)EE企业级开发(JSP,EJB)ME嵌入式开发(手机,小家电) 目前,Java 2平台有3个版本,它们是适用于小型设备和智能卡的Java 2平台Micro版(Java 2 Platform Micro Edition,J2ME).适用于桌面系统的Java 2平台标准版(Java 2

Java、Java SE、Java ME、Java EE

java SE:Java Standard Edition,标准版,开发桌面程序应用.通常说的Java.也是核心.java EE:Java Enterprise Edition,企业版,开发JavaWeb应用程序.java ME:Java Micro Edition,微型版,开发手机等电子产品的应用程序. Q:Java是一种解释型语言.所以效率低,提高性能有2个方法:1.Java语言源程序编写完成后,先使用Java伪编译器进行伪编译,将其转换为中间码(也称为字节码)再解释.2.提供一种“准实时”

JAVA SE、JAVA EE、JAVA ME的联系与区别

Java 平台有三个版本,这使软件开发人员.服务提供商和设备生产商可以针对特定的市场进行开发: * Java SE(Java Platform,Standard Edition).Java SE 以前称为 J2SE. 它允许开发和部署在桌面.服务器.嵌入式环境和实时环境中使用的 Java 应用程序. Java SE 包含了支持 Java Web 服务开发的类,并为 Java Platform,Enterprise Edition(Java EE)提供基础. * Java EE(Java Plat

JAVA SE、JAVA EE、JAVA ME 三者区别

Java 平台有三个版本,这使软件开发人员.服务提供商和设备生产商可以针对特定的市场进行开发:     * Java SE(Java Platform,Standard Edition).Java SE 以前称为 J2SE.它允许开发和部署在桌面.服务器.嵌入式环境和实时环境中使用的 Java 应用程序.Java SE 包含了支持 Java Web 服务开发的类,并为 Java Platform,Enterprise Edition(Java EE)提供基础.     * Java EE(Jav

Java SE、Java EE、Java ME

Java SE(Java Platform,Standard Edition).Java SE 以前称为 J2SE.它允许开发和部署在桌面.服务器.嵌入式环境和实时环境中使用的 Java 应用程序.Java SE 包含了支持 Java Web 服务开发的类,并为 Java Platform,Enterprise Edition(Java EE)提供基础. Java EE(Java Platform,Enterprise Edition).这个版本以前称为 J2EE.企业版本帮助开发和部署可移植.

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

我们平时使用的一些软件,有一部分需要Java环境的支持,但是SUN那么多的产品,让人眼花缭乱的版本号,前看后看都差不多的缩写,让我们选择起来的时候常常望而却步,只好跟着感觉走.所以下面我要介绍的就是那些让大家困惑的东西,首先让我们看看SUN的产品之多:下载地址:http://developers.sun.com/downloads/ 哈哈还没有展开它们的子选项呢,让人眼花缭乱,下面介绍大家使用的比较广泛的名词吧:(一)J2SEJava2平台标准版(Java2 Platform Standard

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

现在一个个来分析 1. Java SE(Java Platform,Standard Edition).Java SE 以前称为 J2SE.它允许开发和部署在桌面.服务器.嵌入式环境和实时环境中使用的 Java 应用程序.Java SE 包含了支持 Java Web 服务开发的类,并为 Java Platform,Enterprise Edition(Java EE)提供基础. 2. Java EE(Java Platform,Enterprise Edition).这个版本以前称为 J2EE.

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

这个是在别人博客抄的,并不是本人撰写 Java是一门编程语言.Java分为三大版本,SE即标准版,包含了Java核心类库,主要用来开发桌面应用:EE即企业版,包含SE,又有扩展部分(Servlet,JDBC等),主要用来开发分布式网络程序:ME即微型版,包含了SE中部分类库,又有自己扩展部分,主要用来做移动类.嵌入式开发. Java SE(Java Platform,Standard Edition).Java SE 以前称为 J2SE.它允许开发和部署在桌面.服务器.嵌入式环境和实时环境中使用

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

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