Java EE应用的性能问题对严肃的目和品来说是一个非帔R要的问题。特别是企业U的应用Qƈ发用户多Q数据传输量大,业务逻辑复杂Q占用系l资源多Q因此性能问题在企业应用变得臛_重要Q它和系l的E_性有着直接的联pR更加重要的是,性能好的应用在完成相同Q务的条g下,能够占用更少的资源,获得更好的用户体验,换句话说Q就是能够节省费用和消耗,获得更高的利润?/span>
要获得更好的性能Q就需要对原来的系l进行性能调优。对q行在Glassfish上的JavaEE应用Q调优是一件相对复杂的事情。在调优以前必须要认识到Q对JavaEE的系l,调优是多层次的。一个JavaEE的应用其实是整个pȝ中很的一部分。开发h员所开发的JavaEEE序Q无论是JSPq是 EJBQ都是运行在JavaEE应用服务器(GlassfishQ之上。而应用服务器本n也是Java语言~写的,需要运行在Java虚拟Z上?Java虚拟Z只不q是操作pȝ的一个应用而已Q和其他的应用(如ApacheQ对于操作系l来说没有本质的区别。而操作系l却q行在一定的g环境中,包括CPUQ内存,|卡和硬盘等{。在q么多的层次中,每一个层ơ的因素都会影响整个pȝ的性能。因此,对一个系l的调优Q事实上需要同时对每个层次都要调优。JavaEE应用性能调优不仅仅和Glassfish有关QJava语言有关Q还要和操作pȝ以及g都有关系Q需要调优者有l合的知识和技能。这些不同层面的Ҏ需要综合纵效,l合在一LzM用,才能快速有效的定位性能瓉。下面是一些具体的案例分析:
某个JavaEE应用q行?颗CPU的服务器上。上U运行发现性能不稳定。性能随着旉的增加而越来越慢。通过操作pȝ的工PmpstatQ,发现在系l很慢的时候,只有一颗CPU很忙Q其他的CPU都很I闲。因此怀疑是Java虚拟机经常进行内存回Ӟ因ؓ虚拟机在内存回收的时候,有的回收法通常只能q行在一个CPU上。通过Java虚拟机的工具“jstat”可以清楚的看刎ͼJava虚拟行内存回收的频率非常高,几乎?U中有一ơ,每次回收的时间ؓ2U钟。另外,通过“jstat”的输发现每次回收释放的内存非常有限,大多数对象都无法回收。这U现象很大程度上暗示着内存泄漏。?Java虚拟机的工具“jmap”来获得当前的一个内存映象。发现有很多Q超q?0000Q个的session对象。这是不正常的一个现象。一般来_ session对应于一个用L多次讉KQ当用户退出的时候,session应该失效,对象应该被回收。当我们和这个系l的开发工E师了解有关 session的设|,发现当他们部|应用的时候,竟然session的timeout旉讄?0分钟Qƈ且没有提供logout的接口。这L讄下,每个session的数据都会保?0分钟才会被回收。根据我们的Q系l提供了logout的链接,q且告诉用户如果退出应用,应该点击q个 logout的链接;q且session的timeout旉修改?分钟。通过几天的测试,证明泄漏的问题得到解冟?/p>
某胦务应用运行在JavaEE服务器上Q后台连接Oracle数据库。ƈ发用h量超q?00人左右的时候系l停止响应。通过操作pȝ层面的进E监控工具发现进Eƈ没有被杀L挂vQ而CPU使用率几乎ؓ零。那么是什么原因导致系l停止响应用戯求呢Q我们利用Java虚拟机的工具Qkill -3 pidQ将当前的所有线E状态DUMP出来Q发现JavaEE服务器的大部分处理线E都在等待数据库q接池的q接Q而那些已l获得数据库q接的线E却处于d状态。数据库理员应要求查了数据库的状态,发现所有的q接的session都处于死锁状态。显Ӟq是因ؓ数据库端出现了死锁的操作Q阻塞了那些有数据库操作的请求,占用了所有数据库q接池中的连接。后l的h如果q要从连接池中获取连接,׃d在连接池上。当解决数据库死锁的问题之后Q性能问题q刃而解?/p>
电信应用q行?4位Java虚拟ZQ系l运行得很不E_Q系l经常停止响应。用进E工h看,发现q程q没有被杀L挂v。利用Java虚拟机的工具发现pȝ在长旉的进行内存回Ӟ内存回收的时间长?5分钟Q整个系l在内存回收的时候就像挂起一栗另外还观察到系l用了12G的内存(因ؓ?64位虚拟机所以突破了4G内存的限Ӟ。从开发h员那里了解到Q这个应用ؓ了提高性能Q大量用了对象~存Q但是事与愿q,在Java中用过多的内存Q虽然在正常q行的时候能够获得很好的性能Q但是会大大增加内存回收的时间。特别是对象~存Q本pȝ使用?G的缓存空_q存了6000多万个对象,对这些对象的遍历D了长旉的内存回收。根据我们的Q将~存I间减少?GQƈ调整回收法Q用增量回收的法Q,使得pȝ׃内存回收而造成的最大停时间减到4U,基本满用户的需求?/p>
数字校园应用q行?CPU的Solaris10服务器上Q中间g为JavaEE服务器。系l在做大q发压力试的时候,h响应旉比较慢,通过操作pȝ的工PmpstatQ发现CPU使用率比较高。ƈ且系l占用绝大多数的CPU资源而不是应用本w。这是个不正常的现象Q通常情况下用户应用的CPU占用率应该占主要CQ才能说明系l是正常工作。通过Solaris 10的Dtrace脚本Q我们查看当前情况下哪些pȝ调用p了最多的CPU资源Q竟然发现最pCPU的系l调用是“fork”。众所周知Q?“fork”pȝ调用是用来生新的进E,在Java虚拟Z只有U程的概念,l不会有q程的生。这是个非常异常的现象。通过本系l的开发h员,我们扑ֈ了答案:每个用户h的处理都包含执行一个外部shell脚本Q来获得pȝ的一些信息。这是通过Java?#8220;Runtime.getRuntime ().exec”来完成的Q但是这U方法在Java中非常消耗资源。Java虚拟机执行这个命令的方式是:首先克隆一个和当前虚拟ZLq程Q再用这个新的进E去执行外部命oQ最后再退个进E。如果频J执行这个操作,pȝ的消耗会很大Q不仅在CPUQ内存操作也很重。用h据徏议去掉这个shell 脚本执行的语句,pȝ立刻回复了正常?/p>
内容理QCMSQ系l运行在JavaEE服务器上Q当pȝ长时间运行以后,性能非常差,用户h的g时比pȝ刚上U的时候要大很多,q且用户的ƈ发量很小Q甚x单个用户也很慢。通过操作pȝ的工兯察,一切都很正常,CPU利用率不高,IO也不是很大,内存很富余,|络几乎没有压力Q因为ƈ发用户少Q。先不考虑U程互锁的问题,因ؓ单个用户性能也不好。通过Java虚拟察也没有发现什么问题(内存回收很少发生Q。这使得我们不得不用代码跟t器来全E跟t代码。我们采用了Netbeans的ProfilerQ跟t的l果非常意外Q用戯求的90Q的旉在创建新文g。从pȝ设计人员了解刎ͼ此系l用了一个目录用于保存所有上传和׃n的文Ӟ文g用其命名方式来唯一区别于其他文件。我们查看了那个文g目录Q发现该目录下已l拥?0万个文g了。这时候我们才定位到问题了Q在同个目录下放|太多的文gQ在创徏新文件的时候,pȝ的开销是比较大的,例如Z防止重名Q文件系l会遍历当前目录下所有的文g名等{。根据我们的Q将文g分类保存在不同的目录下,性能有了大幅度的提高?/p>
q行在JavaEE服务器上的ERPpȝQ在CPU充分利用的情况下性能仍然不太好。从操作pȝ层面上观察不C么大问题Q而且ERPpȝq于复杂Q代码跟t比较困难。于是进行了CPU状态的q一步检查,发现CPU的TLB命中率不是很高,于是对Java虚拟机的启动参数q行了修改,虚拟Z用大寸的内存页面,提高TLB的命中率。下面的参数是在Sun的HOTSPOT中调整大寸Q?MQ页面的讄Q?br />
-XX:+AggressiveHeap
-XX:LargePageSizeInBytes=256m
通过调整QTLB命中明显提高Q性能也得到近40Q的提升?/p>
转蝲之:http://developers.sun.com.cn/blog/yutoujava/entry/8