星期五 九月 12, 2008
Xinfeng Liu
- All
- Java & JES
- 杂谈
- Solaris
- 新闻
使用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上运行的最好,道理就不用说了。
Posted at 02:11上午 九月 12, 2008 by xinfeng liu in Java & JES | Comments[0]
使用SUN Studio编译C++程序几个注意问题
不喜欢C++,不规范的C++代码的移植简直就是一场恶梦,即使是在同一种编译器的不同版本间移植也会令人痛苦不堪。Mozilla甚至给出了一个编码规范,以减少跨平台/跨编译器移植的麻烦。不符合该规范的代码一律被认为BUG,即使代码的功能正确。
不同编译器编出来的C++代码通常是不能混用的。因为C++有个符号mangling的问题,不同的编译器有不同的mangling方法,导致符号不通用。Solaris上的Java虚拟机是用Sun compiler编译的,因此如果你有JNI代码是C++写的,你应该用Sun compiler编译JNI代码。(当然Sun compiler是免费的)。编译各种操作系统平台的JNI代码的建议编译选项见Kelly O'Hair的blog。
Sun compiler编译可执行程序时会自动链接 -lCstd -lCrun -lm -lc ,但编共享库时却不会。所以编共享库时应该显式地加上这些链接选项。
Sun compiler 也同时提供标准C++库的stlport实现,编译时可以加上-library=stlport4以使用stlport的实现而不是自带的libCstd.so.1。但这二者在同一程序中不能混用。
如果用DTrace来调试C++程序,函数名要使用mangle过的符号,因为DTrace不认识C++(mdb也是这样)。想得到mangle过的符号可以通过nm -C <binary name> 得到。如果要跟踪函数的参数,第一个参数通常应该是arg1而不是arg0,因为C++中类成员函数映射成C代码后第一个参数一般都是this指针。比如下面的DTrace脚本跟踪某个函数的调用过程:
#!/usr/sbin/dtrace -qFs
pid$target::__xxxxxx_:entry
{
self->traced=1;
printf("thread #%d is doing %s \n", tid, copyinstr(arg1)); /* suppose arg1 type is char* */
}
pid$target::__xxxxxx_:return
{
self->traced=0;
}
pid$target:::entry
/self->traced/
{
printf("thread #%d is calling %s .\n", tid, probefunc);
}
pid$target:::return
/self->traced/
{
printf("thread #%d returns from %s .\n", tid, probefunc);
}
Posted at 12:52上午 九月 12, 2008 by xinfeng liu in Solaris | Comments[0]
