JAVA性能优化-GC日志分析

2009年6月1日 hashei 1 条评论

前两篇说到IBM JDK和Sun的HotSpot JDK的调优策略,当中一直提到的重要一点是需要根据GC详细日志来调整参数的设置,那么当我们收集到日志后如何分析,如何根据日志的情况来调整参数?这就是本文所要阐述的。

使用IBM的JDK的Windows平台和AIX平台,我们只要在WebSphere管理控制台的java进程属性里勾选“详细垃圾回收”,那么就会在native_stdout.log中生成如下的信息。

image

这幅图很形象的给出了gc日志的主要关注点:垃圾回收的原因、垃圾回收的间隔、垃圾回收前后的剩余空间、垃圾回收持续的时间……

“nursery”表示这次分配失败(Allocation Failure)发生在新生代(nursery),是第44次(id=44)因为新生代的分配失败而进行垃圾回收了(开启GC日志以来),离上一次发生GC的间隔是12746ms,无法分配的空间大小是8216Byte,而进行垃圾回收前,新生代的可用空间为1776Byte,小于8216Byte,虽然年老区还剩余45%的空间,但是新的内存空间是无法直接在年老区分配的,由此引发了一次清理过程(scavenger)。

GC type表明了这次垃圾回收是一个清理过程,也是第44次scavenger过程,同时恰是第44个gc过程,说明没有发生过诸如<gc type=”global”>的垃圾回收过程。flipped objectcount说明将要把4523143个存活下来的对象被复制到了幸存区(survivor space),而73768个对象则经过多次幸存区的复制,有幸熬出头,被转移到了长存区(tenured space)。我们看到清理的倾斜比率(scavenger tiltratio)为89%,而不是对半开,说明经过多次复制清理,JVM已经意识到每次只有很少的对象能存活下来,于是它自动增大了年轻代中Eden区的大小,以使得为新对象可以腾出更多的内存。

接下来的就比较简单,经过垃圾回收,新生代的空间剩余89%,因为分配失败发生在新生代,进行的是快速的Minor gc,所以长存区的可用空间依然是45%,这次回收的时间为384.469ms。在长存区发生的是Major gc,回收时间一般要长于Minor gc,所以健康的JVM 环境Minor gc:Minor gc=1:10(也不用太在意)。

在垃圾回收准备开始的那一段时间(time exclusiveaccessms),以及回收的过程中,另一个线程发现内存无法分配了,于是也要求一次gc过程,这时候就产生了gc队列(会有<warning details=”exclusive access time includes previous garbage collections” />显示)。一般前一次垃圾回收就会释放出足够这两次分配需要的空间,于是第二次gc过程就终止了,当然要是无法足够分配的话,马上就会再进行一次垃圾回收。不过这种情况下,估计要进行Full GC了。

Full GC的gc type就是global,这是stop the world的最耗费时间的回收方式,所以需要通过尽量调整参数来避免。如果发现不是由AF引起的,而是在开头写着SYS标签,那么就要好好问问开发,有没有使用System.gc()的必要?可以的话使用-Xdisableexplicitgc来禁止(Sun等JDK下为-XX:+DisableExplicitGC)。

以上所说的都是IBM JDK下垃圾回收日志的情况。在Sun和HP的JDK下情况相似,不过需要使用-XX:PrintHeapAtGC:参数来打印GC前后的详细堆栈信息。另外我建议加上-Xloggc:filename或者-Xverbosegclog:file_name(方便用工具分析)输出到特定文件,因为不知为何有时候会输出到native_stderr.log,或者在native_stdout.log中和thread dump夹杂在一起,不方便分析。

{Heap before GC invocations=116:
Heap
def new generation   total 157376K, used 139904K [63400000, 6dec0000, 78950000)
eden space 139904K, 100% used [63400000, 6bca0000, 6bca0000)
from space 17472K,   0% used [6bca0000, 6bca0000, 6cdb0000)
to   space 17472K,   0% used [6cdb0000, 6cdb0000, 6dec0000)
tenured generation   total 349568K, used 79067K [38800000, 4dd60000, 632b0000)
the space 349568K,  22% used [38800000, 3d536ce0, 3d536e00, 4dd60000)
compacting perm gen  total 132096K, used 132023K [28800000, 30900000, 38800000)
the space 132096K,  99% used [28800000, 308edf50, 308ee000, 30900000)
[GC 218971K->83116K(506944K), 0.0976948 secs]
Heap after GC invocations=117:
Heap
def new generation   total 157376K, used 4049K [63400000, 6dec0000, 78950000)
eden space 139904K,   0% used [63400000, 63400000, 6bca0000)
from space 17472K,  23% used [6cdb0000, 6d1a4628, 6dec0000)
to   space 17472K,   0% used [6bca0000, 6bca0000, 6cdb0000)
tenured generation   total 349568K, used 79067K [38800000, 4dd60000, 632b0000)
the space 349568K,  22% used [38800000, 3d536ce0, 3d536e00, 4dd60000)
compacting perm gen  total 132096K, used 132023K [28800000, 30900000, 38800000)
the space 132096K,  99% used [28800000, 308edf50, 308ee000, 30900000)
}

这是一个在使用HPJDK输出的实例,基本和IBM JDK没啥区别,可以加上-XX:+PrintGCTimeStamps显示每次回收的间隔。

这些“人肉”分析可以让我们清楚JVM运行的情况,但是还是不够直观,所以下次会介绍分析JVM日志的工具,尽情期待。现已完成,欢迎访问

JAVA性能优化—编写符合GC胃口的程序

2009年5月30日 hashei 没有评论

JAVA性能优化—IBM JDK JVM参数设置JAVA性能优化—Sun’s Hostspot JVM参数设置两篇文章中我介绍了针对JDK进行优化的方法,这些参数上的改变也许会带来50%甚至100%的性能提升,但是如果从程序入手,可能提升的空间是一个数量级的,而且往往很多时候性能问题光靠调整参数无法解决。接下来分享两篇文档,指点你写出更符合JVM GC“胃口”的代码。

javaProgrammingPerformanceTips

  1. Primitive and Objects
  2. Abuse of the String class
  3. Creating intermediate objects
  4. Mutable return types
  5. Using the wrong collections
  6. Array copy

         GCFriendlyProgramming

  1. Garbage Collection
  2. Programming Tips
  3. Problems With Finalization
  4. Using Reference Objects
  5. Conclusions

          详细内容各位自己看吧,对于编程我也是门外汉。

JAVA性能优化—Sun Hotspot JDK JVM参数设置

2009年5月29日 hashei 5 条评论

本文主要根据这篇PDF(GCTuningGuidelines)写成。

首先是JDK1.5引入的新功能 Ergonomic Settings(自动优化的参数)

对于有2块CPU和2GB内存及更佳配置的服务器,Sun的hotspot jdk默认设置了如下参数:

  • -server :服务器模式编译
  • -XX:+UseParallelGC 并行收集
  • -Xms设置为服务器物理内存的1/64
  • -Xmx设置为服务器物理内存的1/4(最大为1G)

我在网上发现了这篇文章,也是根据那篇PDF写的,基本都翻译过来了,那我就不再做造轮子的过程了。有些自己的想法会用红色标出。

摘自         http://unixboy.javaeye.com/

原文链接 JVM调优总结 -Xms -Xmx -Xmn -Xss

  1. 堆大小设置 JVM 中最大堆大小有三方面限制:相关操作系统的数据模型(32-bt还是64-bit)限制;系统的可用虚拟内存限制;系统的可用物理内存限制。32位系统 下,一般限制在1.5G~2G;64为操作系统对内存无限制。我在Windows Server 2003 系统,3.5G物理内存,JDK5.0下测试,最大可设置为1478m。

    典型设置(例子中的堆分配的都比较大,注意自己平台的限制,下文同)

    • java -Xmx3550m -Xms3550m -Xmn2g -Xss128k-Xmx3550m:设置JVM最大可用内存为3550M。

      -Xms3550m:设置JVM促使内存为3550m。此值可以设置与-Xmx相同,以避免每次垃圾回收完成后JVM重新分配内存(就是收缩和扩张,分代回收加上Sun内存分配的算法,避免了IBM JDK最小堆和最大堆一样上的缺陷,但是这对-Xms和-Xmx的设置有了更高的要求,应该是多次试验确定一个合适的大小)。

      -Xmn2g:设置年轻代大小为2G。整个堆大小=年轻代大小 + 年老代大小 + 持久代大小。持久代一般固定大小为64m,所以增大年轻代后,将会减小年老代大小。此值对系统性能影响较大,Sun官方推荐配置为整个堆的3/8。从下图,应该可以看到整个堆大小=年轻代大小 + 年老代大小,Xms和Xmx不包括Perm Size。

    阅读全文…

WebSphere的类加载机制和故障排查

2009年5月27日 hashei 没有评论

在部署WebSphere应用的过程中,经常会发生诸如:ClassCastException、ClassNotFoundException、NoClassDefFoundException、UnsatisfiedLinkError的错误。这种有关“类”(Class)的错误,往往来无影——开发环境好的,怎么在生产环境就有问题;而且去无踪——单独建立一个Profile部署一下就没问题了,把Jar包换个目录就OK了。其实要解决这些怪异的问题,首先要了解WebSphere的类加载(Class loader)机制。

下文主要内容来自http://publib.boulder.ibm.com/infocenter/wasinfo/v6r0/index.jsp?topic=/com.ibm.websphere.nd.doc/info/welcome_nd.html 和IBM developworks中的《如何在WebSphere中解决jar包冲突》一文,我把个人觉得最容易理解的部分总结在一起,方便学习和快速的解决问题。

使用的类装入器以及使用顺序

WebSphere Application Server 的运行时环境按以下顺序使用下列类装入器来查找和装入应用程序的新类:

  1. Java 虚拟机创建的引导程序、扩展和 CLASSPATH 类装入器引导程序类装入器使用引导类路径(通常是 jre/lib 中的类)找到并装入类。扩展类装入器使用系统属性 java.ext.dirs(通常是 jre/lib/ext)找到并装入类。CLASSPATH 类装入器使用 CLASSPATH 环境变量查找和装入类。CLASSPATH 类装入器装入 WebSphere Application Server 产品在 j2ee.jar 文件中提供的 Java 2 Platform, Enterprise Edition(J2EE)应用程序编程接口(API)。由于这个类装入器装入 J2EE API,所以,可以将依赖于 J2EE API 的库添加到类路径系统属性中以扩展服务器类路径。但是,扩展服务器的类路径的首选方法是添加共享库
  2. WebSphere 扩展类装入器WebSphere 扩展类装入器装入在运行时需要的 WebSphere Application Server 类。扩展类装入器使用 ws.ext.dirs 系统属性来确定装入类时所使用的路径。ws.ext.dirs 类路径中的每个目录和这些目录中的每个 Java 归档(JAR)文件或 ZIP 文件都添加到此类装入器使用的类路径中。如果安装在服务器上的应用程序模块引用了与资源提供程序相关联的资源,并且该提供程序指定了资源驱动程序的目录名称,那么 WebSphere 扩展类装入器还将资源提供程序类装入到服务器中。
  3. 一个或多个应用程序模块类装入器,它们负责装入在服务器中运行的企业应用程序的元素应用程序元素可以是 Web 模块、企业 bean(EJB)模块、资源适配器归档(RAR 文件)和依赖项 JAR 文件。应用程序类装入器按照 J2EE 类装入规则从企业应用程序装入类和 JAR 文件。WebSphere Application Server 允许使共享库与应用程序相关联。
  4. 零个或多个 Web 模块类装入器缺省情况下,Web 模块类装入器装入 WEB-INF/classes 和 WEB-INF/lib 目录的内容。Web 模块类装入器是应用程序类装入器的子代。可以指定使用应用程序类装入器来装入 Web 模块的内容,而不是使用 Web 模块类装入器来装入这些内容。

阅读全文…

抵抗诱惑——系统管理员的时间管理

2009年5月26日 hashei 没有评论

       I Can Resist Everything Except Temptation

                                                                —— Oscar Wilde

       最近工作比较清闲,就免不得胡思乱想,想个人今后的职业发展,想如何更好的利用现在这段还算年轻自由的时光。“年轻人是不是应该为梦想殊死搏斗?”这是某位老大的疑问。如果说梦想是隐隐绰绰,看的见却抓不着,或者只是留下“别和我谈理想,已经戒了”的无奈,那么一个切实可行的目标总该有的吧。谁不想在公司里成为举足轻重的骨干,谁不愿兜里的钱能多一些,谁不希望有个幸福美满的家庭?

       我是都想的,看看离而立之年只有5年的时光,总感到一阵阵紧迫感。但是自己这种天塌下来都悠哉游哉的性格,做啥事一会会后就想着“不要着急不要着急,休息休息一下”的半吊子态度,让我自己都觉得实在是可恶至极。

其实我们都知道自己的弱点,但是知道是一回事,克服又是另一回事了——至少在没有旁人督促的情况下。而当我看到这本《时间管理-给系统管理员》的时候,我知道了督促的关键不是是否有个人一直在背后催着,而是是否有一个完善的计划。

  1. 切实可行的长期计划(个人和职业)
  2. 如何在8小时内安排好100小时任务量的计划——优先级管理
  3. 如何专心工作,避免打扰的计划
  4. 如何不会被会议、邮件占用整个一天的计划
  5. 如何避免把时间都浪费在“开心网”上的计划
  6. 如何把自己的大脑从繁杂的记忆中解放出来的计划

……

时间管理的关键就是GTD(Get things Done),现在已不新鲜,但从此书中点出则让我倍感亲切,因为它是一本针对我的书——Time Managerment for System Administrators。但是要谨记的一点是:养成一个习惯需要21天。所以如何避免一暴十寒是我接下去能否成功的重点。

现在我面临的诱惑很多:每天“开心网”的偷菜种菜、转帖的八卦新闻,订阅的大量博客,MSN上闪闪发亮的头像。所以执行力(又见执行力)是关键。可以说,我现在开的这个博“聚沙成塔—小哈的记事簿”,也是贯彻执行力的一个手段。唯有要把自己的知识写出来而又不贻笑大方,才能逼着自己查阅原始资料,务必找到官方明确描述的语句,逼着自己为了理解一些繁琐的英语长句请教英语系的高材生。书写是为了更好的思考为什么你应该(从现在开始就)写博客是我坚持下去的动力,而“刘未鹏 | Mind Hacks 思维改变生活”也必将不会被清理出我的google reader(大家可以看看,他的每一篇文章都可以说是精工细作的结果)。

这篇文章虽说夹杂着人生计划,可到底还是一篇读后感,所以也不得不吐槽一下“糟糕”的翻译。文中时时夹杂着生硬的如机器翻译的语句,如“我是一个新鲜人”,那些每章开头都有的漫画我也没看出什么笑点来。不过万幸的是,这不是一部文学作品,而且有意思的是,如果你读到无法理解的句子,试着将它译回英文(一个词一个词翻译就好了)你会豁然开朗。

WebSphere遗忘管理控制台密码怎么办?外一篇其它各种密码的补救措施

2009年5月25日 hashei 没有评论

常在河边走,哪有不湿鞋,WebSphere管理中最让人无语的是把密码忘记了。管理控制台也好,数据源的密码也好,配置的时候为了满足安全管理的要求设置了8位以上、大小写皆有、毫无意义的密码,现在两眼一抹黑,怎么都试不出来。怎么办?重装?生产环境好不好。其实不用着急,IBM还是给我们留了一条后路的。

管理控制台密码遗忘有两种补救措施:

方法一:命令行——从$WAS_HOME/profiles/xxx 概要文件名/bin目录下,运行 wsadmin -conntype NONE 。当wsadmin的命令行窗口出现之后,运行 securityoff 。上述操作在应用服务器启动或停止的状态都能发出。再次启用WAS时,就是停用管理安全性的状态了。

方法二:修改配置文件——修改$WAS_HOME\config\cells\xxx 下的security.xml,把第一个enable改成false就取消安全性了。

详细说明 http://www-01.ibm.com/support/docview.wss?uid=swg21105430

以上两种方法是禁用了全局安全性(global security),最后别忘了设置新的密码然后再次启用。

下文是讲述如何“破解”出WebSphere中其它密码的方法:

转自Sunny’s 部落格

http://www.sunnyblog.info/blog/archives/3149

WebSphere会在配置文件(一堆的XML)当中存放各种密码(包括数据源、认证别名等等),例如在$WAS_Profile_HOME\config\cells\security.xml文件里面有类似”<authDataEntries xmi:id=”JAASAuthData_1238489272531″ alias=”myNode01/oracleDBA” userId=”oraadmin” password=”{xor}bm1sa2pp”/>”,就是存放认证别名为oracleDBA的用户名和密码。

可以看到在这里密码被重新编码(encode)了,编码的方式是XOR(eXclusive OR异或),很明显这种并不是一种强加密的算法,仅仅是一种编码而已,所以准确来说WebSphere为了避免密码被明文记录,只是很简单地“编码”(encode)而不是“加密”(encrypt)。

万一阁下一个不小心忘记了存放在WebSphere里面的密码,但是又想恢复过来的话,WebSphere这种只是编码而不是加密的存放密码形式,就帮助了你了。当然如果你想干坏事的话,WebSphere也算是给自己留下了一个“后门”了 -_-b。嘿嘿嘿,不要以为IBM那帮老爷子就是这么懒,如果阁下真的是要对存放在WebSphere配置文件里面的密码要加密的话(对于广大客户肯定是有这个诉求的),其实IBM也提供了一种自定义加密算法的插件形式去解决这个问题的,详情可以参考这个链接,在这里就不对这个问题进行展开讨论了。

好了,现在就对各个版本的WAS的密码编码和反编码进行讨论:

WAS 5.X的编码:

> cd $WAS_INSTALL_DIR/lib
> ../java/bin/java -cp securityimpl.jar:iwsorb.jar com.ibm.ws.security.util.PasswordEncoder 123456

WAS 5.X的反编码:

> cd $WAS_INSTALL_DIR/lib
> ../java/bin/java -cp securityimpl.jar:iwsorb.jar com.ibm.ws.security.util.PasswordDecoder {xor}bm1sa2pp

WAS 6.0的编码:

> cd $WAS_INSTALL_DIR/lib
> ../java/bin/java -cp securityimpl.jar:iwsorb.jar::ras.jar:wsexception.jar:bootstrap.jar:emf.jar:ffdc.jar com.ibm.ws.security.util.PasswordEncoder 123456

WAS 6.0的反编码:

> cd $WAS_INSTALL_DIR/lib
> ../java/bin/java -cp securityimpl.jar:iwsorb.jar::ras.jar:wsexception.jar:bootstrap.jar:emf.jar:ffdc.jar com.ibm.ws.security.util.PasswordDecoder {xor}bm1sa2pp

WAS 6.1的编码:

> cd $WAS_INSTALL_DIR/bin\ProfileManagement\plugins\com.ibm.websphere.v61_6.1.200
> java -cp ws_runtime.jar com.ibm.ws.security.util.PasswordEncoder 123456

WAS 6.1的反编码:

> cd $WAS_INSTALL_DIR/bin\ProfileManagement\plugins\com.ibm.websphere.v61_6.1.200
> java -cp ws_runtime.jar com.ibm.ws.security.util.PasswordDecoder  {xor}bm1sa2pp

以上内容参考转载自robertmaldon

当然,如果你觉得很麻烦的话,其实也有一个网站直接帮你解码:WebSphere Password Decoder