Thursday, August 16, 2007

OutOfMemory:PermGen Space异常的处理和分析



Java程序员没有遇到过OutOfMemory简直就是不可能的事情!

可见在Java的世界中,太多的不确定因素导致Java运行程序直接崩溃,直接抛出OutOfMemory异常,而一旦遇到了这个问题,调查起来就非常的困难。在JDK 5.0以前,OutOfMemory只有这么一句话: java.lang.OutOfMemory Exception...基本上无从下手,无从分析。从JDK 5.0以后对OutOfMemory增加了许多的详细说明,为这个异常的分析提供了很大的便利。

这次遇到的问题就是会抛出OutOfMemory:PermGen Space的异常,这个异常非常有意思,根据【此文章】的描述,这是一个Sun JVM的bug,从2003年开始,一只到现在都没有解决。而且提出来的解决方案是使用JRockit。Bug产生的原因已经找到,就是因为JVM在分配PermGen Space的时候出现了PermGen Space不足的情况,默认情况下 PermGen的大小为64M,在不换用JRockit的情况下,可以在启动JVM的时候添加一个参数: -XX: MaxPermSize= 128m| 256m| 512m。

那么究竟什么是PermGen呢?

PermGen 原来是指Permanent Generation,本身是在Java的垃圾收集机制(GC)中产生的一个概念。Java的垃圾收集机制最早只是遍历所有的对象,如果发现某个对象没有被引用,则回收,这是在早期的Java 1.0和Java 1.1的时候的GC规则。慢慢的,这样一种“愚蠢的”GC算法成为了JVM性能的瓶颈,在拥有大量数据的Java应用程序中,GC的算法被高度强化,于是各种各样高效的JVM GC算法被发展了起来。从J2SE也就是Java 1.2开始,JVM引入了多种GC算法,其中一种用的非常多的就是Generational Collection,中文也叫做“分代收集法”。

分代收集法摈弃了对所有对象的遍历,而是采用一些经验属性去避免额外的工作(While naive garbage collection examines every live object in the heap, generational collection exploits several empirically observed properties of most applications to avoid extra work)。其中导入了一个非常关键的概念:infant mortality (幼儿死亡率),这表示越是新生成的变量或者对象,越容易被收集。下面一张图表示了对象的生命周期,横轴表示的是测试到对象的生命周期,纵轴表示在一个指定的生命周期上被回收的对象数量。

Histogram of lifetime

可以看到,在使用了分代收集法以后,年轻一代的对象被收集的比例最高。并且在内存中的对象会按照不同的“年龄”来划分,当一个年龄段的对象满了以后,在这个年龄段上就会发生垃圾收集,从最年轻的一代开始,一直到“永生代”,在内存中,所有的对象可以划分为很多代,最后的一代“永生代”就是“Permanent Generation”,这里就是直接引出“Permanent Generation”概念的地方。具体可以参考下图:



根据前面所说的情况,在分代垃圾收集的情况下会产生Permanent Generation的概念,而这个分代垃圾收集法是并行收集和并发收集的基础,所以Permanent Generation会一直存在,那么这个Permanent Generation究竟是做什么用的呢?这里保存了JVM中所有对象的类信息,包括类的元数据,还有方法描述等等,所以这一代内存垃圾收集算法是不一样的,在Java大程序的情况下,尤其是J2EE 或者说Java EE的大型应用程序上,Permanent Generation的大小会直接限定能载入类的数量和大小。

【解决办法】就是设定JVM启动的时候参数,可以如下设置:
java -XX: PermSize=64m -XX: MaxPermSize=128m

另外PermSize 和MaxPermSize如果设置为相同还可以在一定程度上提高性能,因为,PermSize在不断的变化中会需要转移其中的数据。如果固定了以后,则可以减少每次扩大PermSize带来的性能损失。

更多的请参考 【Java官方站点】

另外,还可以在Java启动的时候添加下面的参数来看GC的运行情况:
Java -verbosegc

(完)

Monday, August 13, 2007

My Dear Waiting

Thanks to xiayuan, thank u to make this wonderful flash album for waiting and thus I have chance to view so many lovely pictures.

2 view lovely waiting's historical growth, click me.

Saturday, August 11, 2007

Part II: How to use JConsole



接着前一篇Blog,现在JConsole已经可以启动了。而且JMX的配置方面也整理了一下。JConsole的具体使用界面上,有以下这样的一些截图:

连接上远端的JVM以后可以通过JConsole看到如下截图:



图1:“概述"界面



图2:“内存"界面



图3:“线程"界面



图4:“类"界面



图5:“VM 摘要"界面



图6:“MBean"界面

前面的5个标签页,主要通过图表的方式,将JVM的运行状况用图表的方式表示出来,可以看到内存,CPU,线程,类的概况,以及各个方面的详细图表情况,这样的图表方式可以非常方便的看到系统运行时的压力以及瓶颈在哪里。

第六张标签页显示了MBean的情况,MBean是JMX体系下的一种JavaBean,可以通过MBean所提供的方法,获取某个具体对象的运行情况,甚至可以得到一些对象的Dump数据。MBean非常的多,使用方法也比较麻烦,具体请参看下面的文章:Overview of Monitoring and Management.

(完)

Friday, August 10, 2007

Part I: How to use JConsole



JConsole是一个JDK中提供的JVM监视与管理的工具,主要是通过JMX来提供监视与管理。

默认情况下,JVM是不启动JMX服务,并提供被监视与被管理的能力的,必须在启动Java程序之前,在Java [opt] [app]中指定JMX的服务。JConsole提供本地和远程的两种监管方式,远程又可以分为直接监视,另外一种是通过JMX的服务器来管理。

根据目前我的需要,我举一个很简单的远程监管例子。因为JConsole本身也要耗费一定的资源,所以用远程方式是比较推荐的。

首先启动JConsole:



(因为在日文系统中,所以显示的为日文)

选择下面的Remote Access,输入host:portNumb的格式,另外输入用户名和密码,用户名和密码存储在<JAVA_HOME>/lib/management目录下,将jmxremote.password.template 复制为management.jmxremote.password(如果需要可以将文件的只读属性打开)。注意:这个文件是放在JRE的lib目录下。修改过以后的内容大致如下:
######################################
# File permissions of the jmxremote.password file
######################################
# ...

monitorRole 333
controlRole 333

另外,默认情况下,SSL是被打开的,需要在被监视的机器上生成相应的SSL证书。在Java中可以使用keytool来生成,具体步骤如下:

  • 在命令行输入 keytool -genkey

  • 其次输入 keytool -certreq 来生成一个签名过的证书

  • 将证书导入 keytool -import

    1. KeyTool具体的用法参考下面两个链接: (Solaris and Linux) (Windows).

    2. 以上第一个命令会产生一个.keystore的文件,保存在c:\documents and setting\<username>\.keystore




其中第三条将需要你将第二步生成的CSR文件提交给VeriSign这样公司验证,然后返回给你一个可以使用CER证书,然后在Import,我们主要目的是为了体验JConsole,所以这一步我们就略过。所以我们设定不使用SSL,具体设置如下:
-Dcom.sun.management.jmxremote.authenticate=false
-Dcom.sun.management.jmxremote.ssl=false

注意:这两行将使用非认证,非SSL的情况,在真实的服务器上要小心,很容易留下漏洞的。

在Windows系统下,如果你将Tomcat安装为服务模式,则可以在右下角Tray 图标中点击配置Tomcat,可以在例如下图的属性中配置,非常的简单:



如果不使用Windows系统,则需要在Catalina.bat中改写Java运行的参数。

改完了Tomcat的配置,启动Tomcat。

在远程机器上点击JConsole的连接即可。JConsole的具体使用以及分析下次继续。

-------------------------------------------------------
JMX 的配置主要在Java程序启动的时候使用,这里重新整理了一下,更加清晰易懂一些:

方法1: 最简单的方式:不用密码,不用SSL
-Dcom.sun.management.jmxremote.authenticate=false
-Dcom.sun.management.jmxremote.ssl=false
-Dcom.sun.management.jmxremote.port=<define a random port>

方法2: 使用密码,不用SSL
-Dcom.sun.management.jmxremote.authenticate=true
-Dcom.sun.management.jmxremote.password.file=../conf/jmxremote.password
-Dcom.sun.management.jmxremote.access.file=../conf/jmxremote.access

$CATALINA_BASE/conf/目录下添加jmxremote.password文件,并添加下面两行:

monitorRole <Your password>
controlRole <Your password>

$CATALINA_BASE/conf/目录下添加jmxremote.access文件,并添加下面两行:

monitorRole readOnly
controlRole readWrite

这两种方法是最简单的,并且第二种方法具有一定的安全性。具体可以参考Tomcat的文档:Monitoring

Thursday, August 9, 2007

Java的性能调校



以前做Java的项目,基本上不会遇到对性能进行调校的事情,但是最近遇到了一个比较严重的问题。具体情况不便详细说,但是大致情况如下:

  • Server: Intel Xeon Duo 2 *2

  • Memory: 4G

  • Disk: 3500G

  • JDK: 1.5.0_02

  • Web Server: Tomcat 5.5.19

  • Application: Some kind of OpenSource Project A which contains about 27M's package.


在Tomcat中配置了虚拟主机,运行了4份A的独立版本。运行起来以后,内存占用3G左右,在安装第5份的时候出现OutOfMemory的异常,由此引发了JVM性能调校的课题。

首先找到了一片比较浅显的文档:

其中提到了性能调校的几个要点:

  • 在所有对JVM的调校进行之前,先做以下的检查:

    1. 是否使用了最新的Java Release?

    2. Java是否更新到了最新的update?

    3. OS的补丁是否已经更新到最新?

    4. OS中是否还跑着其他许多不需要的应用程序?



  • 其次对JVM进行以下的调校:

    1. 是否使用了Server HotSpot?

    2. 有没有使用并行GC?(ParallelGC)

    3. 初始化堆内存(heap size)大小是多少?推荐使用物理内存的1/64

    4. 最大堆内存(heap size)是多少?推荐使用物理内存的1/4



  • 调校之前一定要准确的收集系统的运行情况数据并进行分析

    1. 可以参考使用JVM的管理与监视相关文档




在这样的指导下。我准备对我的系统做以下的操作步骤:

  • 使用JConsole观察Tomcat中JVM的使用情况,并进行分析

  • 使用jvmstat观察并进行分析

  • 在Tomcat的运行参数中添加 -Xprof 参数,进行Profiling


在Java tuning white paper中直接提到了一些GC调整的方式,在使用了ParallelGC以后,系统的运行确实能提高不少,但是具体的仍然有问题,等我的Monitoring和Profiling结束以后再报告。

Restart my blogging

Keeping going Tonny!

From Nov 2006 till now, I didn't write a single post, and now, I gonna restart my blogging life.

and I will stick to blogging until I feel tired again.