Xinfeng Liu

http://developers.sun.com.cn/blog/lxf/date/20080912 星期五 九月 12, 2008

使用Sun Studio 和Solaris工具解决Java的性能问题

Sun Studio的performance analyzer是能同时对JVM和Java代码的profiling工具,而且比 起那些基于Java的Profiling工具要好用的多。使用Netbeans Profiler时候最好把项目工程放进Netbeans IDE里才好用,否则不方便对被profiling的应用做细粒度的profiling控制,导致大型应用被profiling后运行非常慢。而Sun Studio的performance analyzer对应用性能的影响要小得多,而且使用起来很简便。只要 collect -j on java <arguments> 就可以了。运行完后会生成一个结果数据目录比如test.1.er,然后用analyzer test.1.er 进行图形化的显示和分析,或使用er_print test.1.er进行命令行的显示。

Sun Studio performance analyzer对java profiling结果的分析,可以按三种模式显示: user, expert, machine。因此可以同时分析用户的Java代码和JVM的C++代码。如果你要分析JNI的代码,这个工具更是离不开了。下面是一个例子:

er_print test.1.er

(er_print) limit 20
(er_print) func
Functions sorted by metric: Exclusive User CPU Time

Excl.     Incl.      Name
User CPU  User CPU
   sec.      sec.
763.864   763.864    <Total>
218.053   218.053    <JVM-System>
 44.511    44.581    <Unknown>
 33.123    35.195    oracle.jdbc.driver.NumberCommonAccessor.getBigDecimal(int)
 21.145    52.287    oracle.jdbc.driver.ClobAccessor.getString(int)
 15.401    30.982    java.util.HashMap.get(java.lang.Object)
 14.630    20.364    sun.nio.cs.UTF_8$Encoder.encodeArrayLoop(java.nio.CharBuffer, java.nio.ByteBuffer)
 13.209    13.259    oracle.jdbc.driver.OracleStatement.prepareAccessors()
 13.159    81.157    org.apache.jsp.home_jsp._jspService(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
 12.429    15.271    oracle.jdbc.driver.T4C8TTIClob.read(byte[], long, long, boolean, char[])
 12.369    16.121    java.lang.String.regionMatches(boolean, int, java.lang.String, int, int)
 11.258    11.258    java.lang.String.equals(java.lang.Object)
 10.667    10.667    java.lang.Throwable.<init>()
  9.517     9.517    oracle.jdbc.driver.T4CConnection.createClobDBAccess()
  8.856    30.671    oracle.jdbc.driver.OracleStatement.getColumnIndex(java.lang.String)
  6.364     6.364    java.lang.String.indexOf(int, int)
  5.844    21.935    java.lang.String.equalsIgnoreCase(java.lang.String)
  5.674     5.674    java.nio.CharBuffer.arrayOffset()
  4.733     4.733    java.util.Arrays.copyOfRange(char[], int, int)
  4.703     4.703    oracle.net.ns.DataPacket.getDataFromBuffer(byte[], int, int)

(er_print) viewmode expert
(er_print) func
Functions sorted by metric: Exclusive User CPU Time

Excl.     Incl.      Name
User CPU  User CPU
   sec.      sec.
763.864   763.864    <Total>
 33.123    35.195    oracle.jdbc.driver.NumberCommonAccessor.getBigDecimal(int)
 21.145    52.287    oracle.jdbc.driver.ClobAccessor.getString(int)
 19.534    19.534    lwp_yield
 17.232    17.232    OopStarTaskQueueSet::peek()
 15.401    30.982    java.util.HashMap.get(java.lang.Object)
 14.630    20.364    sun.nio.cs.UTF_8$Encoder.encodeArrayLoop(java.nio.CharBuffer, java.nio.ByteBuffer)
 13.980    21.855    PhaseChaitin::build_ifg_physical(ResourceArea*)
 13.209    13.259    oracle.jdbc.driver.OracleStatement.prepareAccessors()
 13.159    81.137    org.apache.jsp.home_jsp._jspService(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
 13.129    13.289    IndexSetIterator::advance_and_next()
 12.429    15.271    oracle.jdbc.driver.T4C8TTIClob.read(byte[], long, long, boolean, char[])
 12.369    16.121    java.lang.String.regionMatches(boolean, int, java.lang.String, int, int)
 11.258    11.258    java.lang.String.equals(java.lang.Object)
 10.667    10.667    java.lang.Throwable.<init>()
  9.517     9.517    oracle.jdbc.driver.T4CConnection.createClobDBAccess()
  8.856    30.671    oracle.jdbc.driver.OracleStatement.getColumnIndex(java.lang.String)
  7.475     7.475    arrayof_oop_disjoint_arraycopy
  6.585     8.736    PhaseChaitin::Split(unsigned)
  6.364     6.364    java.lang.String.indexOf(int, int)

(er_print) viewmode machine
(er_print) func
Functions sorted by metric: Exclusive User CPU Time

Excl.     Incl.      Name
User CPU  User CPU
   sec.      sec.
763.864   763.864    <Total>
111.688   546.232    Interpreter
 57.850    60.702    typeArrayKlass::allocate(int,Thread*)
 20.324    20.394    sun.nio.cs.UTF_8$Encoder.encodeArrayLoop(java.nio.CharBuffer, java.nio.ByteBuffer)
 19.534    19.534    lwp_yield
 17.232    17.232    OopStarTaskQueueSet::peek()
 16.291    16.291    java.lang.String.regionMatches(boolean, int, java.lang.String, int, int)
 14.850    31.062    oracle.jdbc.driver.OracleStatement.getColumnIndex(java.lang.String)
 13.980    21.855    PhaseChaitin::build_ifg_physical(ResourceArea*)
 13.129    13.289    IndexSetIterator::advance_and_next()
 11.638    11.638    java.lang.String.equals(java.lang.Object)
 11.588    15.000    java.lang.Object.hashCode()
  7.475     7.475    arrayof_oop_disjoint_arraycopy
  6.585     8.736    PhaseChaitin::Split(unsigned)
  6.545     6.545    java.lang.String.indexOf(int, int)
  5.754     5.754    jshort_disjoint_arraycopy
  5.484     5.484    flush_callers_register_windows
  5.324    16.742    java_lang_Throwable::fill_in_stack_trace(Handle,Thread*)
  5.284     5.284    memcpy
  5.014    18.333    java.util.Collections$SynchronizedMap.get(java.lang.Object)

有时,单单通过Java本身的工具(如jstat, jmap, jinfo, jconsole, java thread dump等)不足以分析出问题,还是需要依靠操作系统的工具来定位。比如pstack, prstat -mL -p <pid>,pmap -xs, DTrace等。假如通过prstat发现Java应用总是不能充分利用CPU,可以通过一个简单的DTrace脚本来找出原因:

offcpu.d
--------
#!/usr/sbin/dtrace -s
off-cpu
/pid == $target/
{
@[jstack(20,200)]=count();
}
tick-2sec
{
trunc(@,10);
printa(@);
clear(@);
}

# ./offcpu.d -p <java process id>

无论你愿不愿意承认,总之Java在Solaris上运行的最好,道理就不用说了。 


Comments:

Post a Comment:
  • HTML Syntax: NOT allowed