怎么使用jvisualvm 线程死锁进行性能分析

用JvisualVM进行性能分析 -
- ITeye技术网站
博客分类:
1、本地机器的程序直接可以监听到
2、远程机器的程序需要加上JVM参数
-Dcom.sun.management.jmxremote= true
-Dcom.sun.management.jmxremote.port= 9090
-Dcom.sun.management.jmxremote.ssl= false
-Dcom.sun.management.jmxremote.authenticate= false
备注:另外需要检查
hostname –i
看解析出来是否为本地的IP,如是127.0.0.1或者IP为多个IP中之一,则其他的IP无效,会连接不上。
这里有个分析案例,利用jvisualvm分析tomcat的问题:
tools-&plugin-&Available Plugin 会有值得安装的插件,如: JConsole
插件列表:
注意:上面提供的端口配置有些麻烦,不如直接这样做:
必须在远程机上启动jstatd代理程序,否则会显示 “not supported for this jvm” 错误
而启动 jstatd 时会有一个权限问题,需要做如下修改:
nano /opt/sun-jdk- 1.6 . 0.26 /jre/lib/security/java.policy
nano /opt/sun-jdk-1.6.0.26/jre/lib/security/java.policy
增加下列行
grant codebase "file:${java.home}/../lib/tools.jar" {
permission java.security.AllP
然后启动 jstatd并且不要关闭
查看线程的运行情况,运行、停止、睡眠、等待,根据这些结合实际程序运行的逻辑分析。
找到可疑份子,可以Thread Dump
找出具体是哪个线程在作祟。
参看这个例子:
关于如何使用,如何分析程序,可以参看这个例子:
浏览: 7297 次
来自: 广州
为什么还是没有~Java性能调优工具 - 推酷
Java性能调优工具
1、JDK命令行工具 & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & &&
1.1、jps命令
jps用于列出Java的进程,jps可以增加参数,-m用于输出传递给Java进程的参数,-l用于输出主函数的完整路径,-v可以用于显示传递给jvm的参数。
jps -l -m -v
31427 sun.tools.jps.Jps -l -m -v -Dapplication.home=/Library/Java/JavaVirtualMachines/jdk1.7.0_55.jdk/Contents/Home -Xms8m
1.2、jstat命令
jstat是一个可以用于观察Java应用程序运行时信息的工具,它的功能非常强大,可以通过它查看堆信息的详细情况,它的基本使用方法为:
jstat -&option& [-t] [-h&lines&] &vmid& [&interval& [&count&]]
选项option可以由以下值组成:
jstat -class pid:显示加载class的数量,及所占空间等信息。
jstat -compiler pid:显示VM实时编译的数量等信息。
jstat -gc pid:可以显示gc的信息,查看gc的次数,及时间。其中最后五项,分别是young gc的次数,young gc的时间,full gc的次数,full gc的时间,gc的总时间。
jstat -gccapacity:可以显示,VM内存中三代(young,old,perm)对象的使用和占用大小,如:PGCMN显示的是最小perm的内存使用量,PGCMX显示的是perm的内存最大使用量,PGC是当前新生成的perm内存占用量,PC是但前perm内存占用量。其他的可以根据这个类推, OC是old内纯的占用量。
jstat -gcnew pid:new对象的信息。
jstat -gcnewcapacity pid:new对象的信息及其占用量。
jstat -gcold pid:old对象的信息。
jstat -gcoldcapacity pid:old对象的信息及其占用量。
jstat -gcpermcapacity pid: perm对象的信息及其占用量。
jstat -gcutil pid:统计gc信息统计。
jstat -printcompilation pid:当前VM执行的信息。
除了以上一个参数外,还可以同时加上 两个数字,如:jstat -printcompilation 是每250毫秒打印一次,一共打印6次。
这些参数中最常用的参数是gcutil,下面是该参数的输出介绍以及一个简单例子:
— Heap上的 Survivor space 0 区已使用空间的百分比
— Heap上的 Survivor space 1 区已使用空间的百分比
— Heap上的 Eden space 区已使用空间的百分比
— Heap上的 Old space 区已使用空间的百分比
— Perm space 区已使用空间的百分比
YGC — 从应用程序启动到采样时发生 Young GC 的次数
YGCT– 从应用程序启动到采样时 Young GC 所用的时间(单位秒)
FGC — 从应用程序启动到采样时发生 Full GC 的次数
FGCT– 从应用程序启动到采样时 Full GC 所用的时间(单位秒)
GCT — 从应用程序启动到采样时用于垃圾回收的总时间(单位秒)
实例使用1:
[root@localhost bin]# jstat -gcutil 25444
1.3、jinfo命令
jinfo可以用来查看正在运行的Java应用程序的扩展参数,甚至在运行时修改部分参数,它的基本语法为:
jinfo可以查看运行时参数:
jinfo -flag MaxTenuringThreshold 31518
-XX:MaxTenuringThreshold=15
jinfo还可以在运行时修改参数值:
& jinfo -flag PrintGCDetails 31518
-XX:-PrintGCDetails
& jinfo -flag +PrintGCDetails 31518
& jinfo -flag PrintGCDetails 31518
-XX:+PrintGCDetails
1.4、jmap命令
jmap命令主要用于生成堆快照文件,它的使用方法如下:
& jmap -dump:format=b,file=heap.hprof 31531
Dumping heap to /Users/caojie/heap.hprof ...
Heap dump file created
获得堆快照文件之后,我们可以使用多种工具对文件进行分析,例如jhat,visual vm等。
1.5、jhat命令
使用jhat工具可以分析Java应用程序的堆快照文件,使用命令如下:
& jhat heap.hprof
Reading from heap.hprof...
Dump file created Tue Nov 11 06:02:05 CST 2014
Snapshot read, resolving...
Resolving 8781 objects...
Chasing references, expect 1 dots.
Eliminating duplicate references.
Snapshot resolved.
Started HTTP server on port 7000
Server is ready.
jhat在分析完成之后,使用HTTP服务器展示其分析结果,在浏览器中访问http://127.0.0.1:7000/即可得到分析结果。
1.6、jstack命令
jstack可用于导出Java应用程序的线程堆栈信息,语法为:
jstack -l &pid&
jstack可以检测死锁,下例通过一个简单例子演示jstack检测死锁的功能。java代码如下:
public class DeadLock extends Thread {
protected Object myD
static ReentrantLock south = new ReentrantLock();
static ReentrantLock north = new ReentrantLock();
public DeadLock(Object obj) {
this.myDirect =
if (myDirect == south) {
this.setName(&south&);
if (myDirect == north) {
this.setName(&north&);
public void run() {
if (myDirect == south) {
north.lockInterruptibly();
Thread.sleep(500);
} catch (Exception e) {
e.printStackTrace();
south.lockInterruptibly();
System.out.println(&car to south has passed&);
} catch (InterruptedException e1) {
System.out.println(&car to south is killed&);
} finally {
if (north.isHeldByCurrentThread())
north.unlock();
if (south.isHeldByCurrentThread())
south.unlock();
if (myDirect == north) {
south.lockInterruptibly();
Thread.sleep(500);
} catch (Exception e) {
e.printStackTrace();
north.lockInterruptibly();
System.out.println(&car to north has passed&);
} catch (InterruptedException e1) {
System.out.println(&car to north is killed&);
} finally {
if (north.isHeldByCurrentThread())
north.unlock();
if (south.isHeldByCurrentThread())
south.unlock();
public static void main(String[] args) throws InterruptedException {
DeadLock car2south = new DeadLock(south);
DeadLock car2north = new DeadLock(north);
car2south.start();
car2north.start();
Thread.sleep(1000);
使用jps命令查看进程号为32627,然后使用jstack -l 32637 & a.txt命令把堆栈信息打印到文件中,该文件内容如下:
Full thread dump Java HotSpot(TM) 64-Bit Server VM (24.55-b03 mixed mode):
&Attach Listener& daemon prio=5 tid=0xc803000 nid=0x3307 waiting on condition [0x0000]
java.lang.Thread.State: RUNNABLE
Locked ownable synchronizers:
&DestroyJavaVM& prio=5 tid=0xb80b000 nid=0x1903 waiting on condition [0x0000]
java.lang.Thread.State: RUNNABLE
Locked ownable synchronizers:
&north& prio=5 tid=0xc075000 nid=0x5103 waiting on condition [0xb06000]
java.lang.Thread.State: WAITING (parking)
at sun.misc.Unsafe.park(Native Method)
- parking to wait for
&0xab600& (a java.util.concurrent.locks.ReentrantLock$NonfairSync)
at java.util.concurrent.locks.LockSupport.park(LockSupport.java:186)
at java.util.concurrent.locks.AbstractQueuedSynchronizer.parkAndCheckInterrupt(AbstractQueuedSynchronizer.java:834)
at java.util.concurrent.locks.AbstractQueuedSynchronizer.doAcquireInterruptibly(AbstractQueuedSynchronizer.java:894)
at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireInterruptibly(AbstractQueuedSynchronizer.java:1221)
at java.util.concurrent.locks.ReentrantLock.lockInterruptibly(ReentrantLock.java:340)
at DeadLock.run(DeadLock.java:48)
Locked ownable synchronizers:
- &0xab5d0& (a java.util.concurrent.locks.ReentrantLock$NonfairSync)
&south& prio=5 tid=0xc074800 nid=0x4f03 waiting on condition [0xa03000]
java.lang.Thread.State: WAITING (parking)
at sun.misc.Unsafe.park(Native Method)
- parking to wait for
&0xab5d0& (a java.util.concurrent.locks.ReentrantLock$NonfairSync)
at java.util.concurrent.locks.LockSupport.park(LockSupport.java:186)
at java.util.concurrent.locks.AbstractQueuedSynchronizer.parkAndCheckInterrupt(AbstractQueuedSynchronizer.java:834)
at java.util.concurrent.locks.AbstractQueuedSynchronizer.doAcquireInterruptibly(AbstractQueuedSynchronizer.java:894)
at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireInterruptibly(AbstractQueuedSynchronizer.java:1221)
at java.util.concurrent.locks.ReentrantLock.lockInterruptibly(ReentrantLock.java:340)
at DeadLock.run(DeadLock.java:28)
Locked ownable synchronizers:
- &0xab600& (a java.util.concurrent.locks.ReentrantLock$NonfairSync)
&Service Thread& daemon prio=5 tid=0xc025800 nid=0x4b03 runnable [0x0000]
java.lang.Thread.State: RUNNABLE
Locked ownable synchronizers:
&C2 CompilerThread1& daemon prio=5 tid=0xc025000 nid=0x4903 waiting on condition [0x0000]
java.lang.Thread.State: RUNNABLE
Locked ownable synchronizers:
&C2 CompilerThread0& daemon prio=5 tid=0xd01b000 nid=0x4703 waiting on condition [0x0000]
java.lang.Thread.State: RUNNABLE
Locked ownable synchronizers:
&Signal Dispatcher& daemon prio=5 tid=0xc022000 nid=0x4503 runnable [0x0000]
java.lang.Thread.State: RUNNABLE
Locked ownable synchronizers:
&Finalizer& daemon prio=5 tid=0xd004000 nid=0x3103 in Object.wait() [0xa000]
java.lang.Thread.State: WAITING (on object monitor)
at java.lang.Object.wait(Native Method)
- waiting on &0x5568& (a java.lang.ref.ReferenceQueue$Lock)
at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:135)
- locked &0x5568& (a java.lang.ref.ReferenceQueue$Lock)
at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:151)
at java.lang.ref.Finalizer$FinalizerThread.run(Finalizer.java:189)
Locked ownable synchronizers:
&Reference Handler& daemon prio=5 tid=0xd001800 nid=0x2f03 in Object.wait() [0x7000]
java.lang.Thread.State: WAITING (on object monitor)
at java.lang.Object.wait(Native Method)
- waiting on &0x50f0& (a java.lang.ref.Reference$Lock)
at java.lang.Object.wait(Object.java:503)
at java.lang.ref.Reference$ReferenceHandler.run(Reference.java:133)
- locked &0x50f0& (a java.lang.ref.Reference$Lock)
Locked ownable synchronizers:
&VM Thread& prio=5 tid=0xb83b000 nid=0x2d03 runnable
&GC task thread#0 (ParallelGC)& prio=5 tid=0xb818000 nid=0x2503 runnable
&GC task thread#1 (ParallelGC)& prio=5 tid=0xb819000 nid=0x2703 runnable
&GC task thread#2 (ParallelGC)& prio=5 tid=0xd000000 nid=0x2903 runnable
&GC task thread#3 (ParallelGC)& prio=5 tid=0xd001000 nid=0x2b03 runnable
&VM Periodic Task Thread& prio=5 tid=0xc02e800 nid=0x4d03 waiting on condition
JNI global references: 109
Found one Java-level deadlock:
=============================
waiting for ownable synchronizer 0xab600, (a java.util.concurrent.locks.ReentrantLock$NonfairSync),
which is held by &south&
waiting for ownable synchronizer 0xab5d0, (a java.util.concurrent.locks.ReentrantLock$NonfairSync),
which is held by &north&
Java stack information for the threads listed above:
===================================================
at sun.misc.Unsafe.park(Native Method)
- parking to wait for
&0xab600& (a java.util.concurrent.locks.ReentrantLock$NonfairSync)
at java.util.concurrent.locks.LockSupport.park(LockSupport.java:186)
at java.util.concurrent.locks.AbstractQueuedSynchronizer.parkAndCheckInterrupt(AbstractQueuedSynchronizer.java:834)
at java.util.concurrent.locks.AbstractQueuedSynchronizer.doAcquireInterruptibly(AbstractQueuedSynchronizer.java:894)
at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireInterruptibly(AbstractQueuedSynchronizer.java:1221)
at java.util.concurrent.locks.ReentrantLock.lockInterruptibly(ReentrantLock.java:340)
at DeadLock.run(DeadLock.java:48)
at sun.misc.Unsafe.park(Native Method)
- parking to wait for
&0xab5d0& (a java.util.concurrent.locks.ReentrantLock$NonfairSync)
at java.util.concurrent.locks.LockSupport.park(LockSupport.java:186)
at java.util.concurrent.locks.AbstractQueuedSynchronizer.parkAndCheckInterrupt(AbstractQueuedSynchronizer.java:834)
at java.util.concurrent.locks.AbstractQueuedSynchronizer.doAcquireInterruptibly(AbstractQueuedSynchronizer.java:894)
at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireInterruptibly(AbstractQueuedSynchronizer.java:1221)
at java.util.concurrent.locks.ReentrantLock.lockInterruptibly(ReentrantLock.java:340)
at DeadLock.run(DeadLock.java:28)
Found 1 deadlock.
从这个输出可以知道:
1、在输出的最后一段,有明确的&Found one Java-level deadlock&输出,所以通过jstack命令我们可以检测死锁;
2、输出中包含了所有线程,除了我们的north,sorth线程外,还有&Attach Listener&, &C2 CompilerThread0&, &C2 CompilerThread1&等等;
3、每个线程下面都会输出当前状态,以及这个线程当前持有锁以及等待锁,当持有与等待造成循环等待时,将导致死锁。
1.7、jstatd命令
jstatd命令是一个RMI服务器程序,它的作用相当于代理服务器,建立本地计算机与远程监控工具的通信,jstatd服务器能够将本机的Java应用程序信息传递到远程计算机,由于需要多台计算机做演示,此处略。
1.8、hprof工具
hprof工具可以用于监控Java应用程序在运行时的CPU信息和堆信息,关于hprof的官方文档如下:
2、Visual VM工具 & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & &&
Visual VM是一个功能强大的多合一故障诊断和性能监控的可视化工具,它集成了多种性能统计工具的功能,使用Visual VM可以替代jstat、jmap、jhat、jstack等工具。在命令行输入jvisualvm即可启动visualvm。
打开Visual VM之后,左边导航栏会显示出当前机器所有Java进程:
点击你想监控的程序即可对该程序进行监控,Visual VM的性能监控页一共有以下几个tab页:
概述页会显示程序的基本使用情况,比如,进程ID,系统属性,启动参数等。
通过监视页面,可以监视应用程序的CPU、堆、永久区、类加载器和线程数的整体情况,通过页面上的Perform GC和Heap Dump按钮还可以手动执行Full GC和生成堆快照。
线程页面会提供详细的线程信息,单击Thread Dump按钮可以导出当前所有线程的堆栈信息,如果Visual VM在当前线程中找到死锁,则会以十分显眼的方式在Threads页面给予提示。
抽样器可以对CPU和内存两个性能进行抽样,用于实时地监控程序。CPU采样器可以将CPU占用时间定位到方法,内存采样器可以查看当前程序的堆信息。下面是一个频繁调用的Java程序,我们会对改程序进行采样:
public class MethodTime {
static java.util.Random r=new java.util.Random();
static Map&String,String& map=
map=new HashMap&String,String&();
map.put(&1&, &Java&);
map.put(&2&, &C++&);
map.put(&3&, &Delphi&);
map.put(&4&, &C&);
map.put(&5&, &Phython&);
public String getNameById(String id){
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
return map.get(id);
public List&String& getNamesByIds(String ids){
List&String& re=new ArrayList&String&();
String[] strs=ids.split(&,&);
for(String id:strs){
re.add(getNameById(id));
public List&String& getNamesByIdsBad(String ids){
List&String& re=new ArrayList&String&();
String[] strs=ids.split(&,&);
for(String id:strs){
//A bad code
getNameById(id);
re.add(getNameById(id));
public class NamesByIdsThread implements Runnable{
public void run() {
while(true){
int c=r.nextInt(4);
String ids=&&;
for(int i=0;i&c;i++)
ids=Integer.toString((r.nextInt(4)+1))+&,&;
getNamesByIds(ids);
}catch(Exception e){
public class NamesByIdsBadThread implements Runnable{
public void run() {
while(true){
int c=r.nextInt(4);
String ids=&&;
for(int i=0;i&c;i++)
ids=Integer.toString((r.nextInt(4)+1))+&,&;
getNamesByIdsBad(ids);
}catch(Exception e){
public static void main(String args[]){
MethodTime instance=new MethodTime();
new Thread(instance.new NamesByIdsThread()).start();
new Thread(instance.new NamesByIdsBadThread()).start();
通过Visual VM的采样功能,可以找到改程序中占用CPU时间最长的方法:
默认Visual VM不统计内置对象的函数调用,比如java.*包中的类,如果要统计这些内置对象,单机右上角的设置进行调配。Visual VM虽然可以统计方法的调用时间,但是无法给出方法调用堆栈,Jprofile不仅可以给出方法调用时间,还可以给出方法调用堆栈,较Visual VM更强大。
右击左导航的应用程序,会出现以下菜单:
单机应用程序快照,可以分析当前应用程序的快照,单击堆Dump能够对当前的堆信息进行分析。Visual VM的更多使用方法,可以查看Oracle的官方文档
BTrace插件
BTrace是一款功能强大的性能检测工具,它可以在不停机的情况下,通过字节码注入,动态监控系统的运行情况,它可以跟踪指定的方法调用、构造函数调用和系统内存等信息,本部分打算举一个例子,讲解一下BTrace的使用。要在Visual VM中使用Btrace,首先需要安装Btrace插件,点击工具-&插件即可在线安装,安装后右键应用程序,就会出现如下选项:
点击Trace application,即可进入BTrace插件界面。使用BTrace可以监控指定函数的耗时,以下脚本通过正则表达式,监控所有类的getNameById方法:
import com.sun.btrace.annotations.*;
import static com.sun.btrace.BTraceUtils.*;
public class TracingScript {
private static long startTime = 0;
@OnMethod(clazz=&/.+/&, method=&/getNameById/&)//监控任意类的getNameById方法
public static void startMethod() {
startTime=timeMillis();
@OnMethod(clazz=&/.+/&, method=&/getNameById/&,
location=@Location(Kind.RETURN))//方法返回时触发
public static void endMethod() {
print(strcat(strcat(name(probeClass()), &.&), probeMethod()));
print(& [&);
print(strcat(&Time taken : &, str(timeMillis() - startTime)));
println(&]&);
点击运行,部分输出如下:
MethodTime.getNameById [Time taken : 5]
MethodTime.getNameById [Time taken : 4]
MethodTime.getNameById [Time taken : 7]
MethodTime.getNameById [Time taken : 7]
BTrace除了可以监控函数耗时外,还可以指定程序运行到某一行代码触发某一行为,定时触发行为,监控函数参数等等。
3、MAT内存分析工具 & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & &
MAT是一款功能强大的Java堆内存分析器,可以用于查找内存泄露以及查看内存消耗情况,MAT的官方文档如下:
在MAT中有浅堆和深堆的概念,浅堆是指一个对象结构所占用的内存大小,深堆是指一个对象被GC回收后可以真正释放的内存大小。
通过MAT,可以列出所有垃圾回收的根对象,Java系统的根对象可能是以下类:系统类,线程,Java局部变量,本地栈等等。在MAT中还可以很清楚的看到根对象到当前对象的引用关系链。
MAT还可以自动检测内存泄露,单击菜单上的Leak Suspects命令,MAT会自动生成一份报告,这份报告罗列了系统内可能存在内存泄露的问题点。
在MAT中,还可以自动查找并显示消耗内存最多的几个对象,这些消耗大量内存的大对象往往是解决系统性能问题的关键所在。
具体例子,略,网速太慢,至今还未下好。。
参考书籍:Java程序性能优化
已发表评论数()
&&登&&&陆&&
已收藏到推刊!
请填写推刊名
描述不能大于100个字符!
权限设置: 公开
仅自己可见jstat&-gcutil&pid&2000
2.jmap,查看heap情况,如查看存活对象列表:
jmap&-histo:live&pid&|grep&pany&|less&
或者dump内存用来分析:
jmap&-dump:file=test.bin&pid
3.分析dump的堆文件,可以用jhat:
jhat&test.bin
& 分析完成后可以用浏览器查看堆的情况。这个工具的分析结果还比较原始,你还可以用插件进行图形化分析,或者IBM的.
4.jvisualvm和jconsole: JVM自带的性能分析和监控工具,怎么用?
5.jstack:分析线程堆栈,如
jstack&pid&&&thread_dump
& & 查看CPU最高的线程在干什么的方法结合top和jstack:
6.更多JVM工具,参见官方文档:7.学习使用btrace分析java运行时问题。《》
8.GC日志分析工具:、或者
9.性能分析工具,除了自带的jvisualvm外,还可以用商业的。
11.《》,iteye神贴。
三、Linux工具
3.使用替换top。
4.熟悉下甚至p来分析问题。
5.自动化部署脚本,或者自荐下我的。
1.掌握一门脚本语言,或者,高效解决一些需要quick and dirty的任务:比如读写文件、导入导出数据库、网页爬虫等。注意不是,咔咔。
2.使用Linux或者Mac os系统作为你的开发环境。
3.升级你的“硬件工具”,双屏大屏显示器、SSD、8G内存甚至更多。4.你懂的:
五、如何查找工具?
1.搜索引擎,google或者baidu,《》
2.万能的stack overflow:
3.虚心问牛人。六、最重要的是⋯⋯一颗永不停止学习的心。
& & 最近陆陆续续补充了不少的文档,部分是直接从官方文档里摘抄出来,放在了,有兴趣了解甚至使用meta的可以仔细阅读下,一份目录:
& & Developer
:使用metamorphosis作为twitter storm的spout源
: metamorphosis的python语言客户端。目前只支持发送消息功能。
& & 后续还会继续补充。
& & Java世界里有这样的神器,可以让你避免很多“简单愚蠢”的bug。同样,Clojure世界里也有相应的替代品,这就是今天要介绍的。不过kibit现在还比较年轻,判断的规则较少,但是已经可以使用起来做clojure代码的静态检查。
项目主页:
1.安装lein插件:
lein&plugin&install&jonase/kibit&0.0.2
2.在项目的根目录运行
lein&kibit
kibit会分析项目里所有clojure源码,每个namespace分别分析,例如我分析的输出:
==&mands&==
==&control.core&==
[186]&Consider&(zero?&(:status&(ssh&host&user&cluster&(str&"test&-e&"&file))))&instead&of&(=&(:status&(ssh&host&user&cluster&(str&"test&-e&"&file)))&0)
==&control.main&==
==&leiningen.control&==
[null]&Consider&Integer/parseInt&instead&of&(fn*&[p1__61444#]&(Integer/parseInt&p1__61444#))
[null]&Consider&Integer/parseInt&instead&of&(fn*&[p1__65254#]&(Integer/parseInt&p1__65254#))
& & 显然,kibit一个一个namespace分析过去,并且按照规则对它认为有问题的地方打印出来,并提出建议。例如这里它建议我用(zero?&(:status&(ssh&host&user&cluster&(str&"test&-e&"&file))))
& & 替换control.core里186行的:&(=&(:status&(ssh&host&user&cluster&(str&"test&-e&"&file)))&0)& & 目前kibit大多数是这类代码风格上的检查,还没有做到类似findbugs那样更丰富的检查,例如NPE异常检查等。此外kibit还提供反射检查,任何有反射调用的地方都给出警告。& & kibit是基于实现的,它的规则都放在了,通过defrules宏来定义检查规则,源码中对算术运算的规则定义:(defrules&rules&&[(+&?x&1)&(inc&?x)]&&[(+&1&?x)&(inc&?x)]&&[(-&?x&1)&(dec&?x)]&&[(*&?x&(*&.&?xs))&(*&?x&.&?xs)]&&[(+&?x&(+&.&?xs))&(+&?x&.&?xs)])& && & 第一个规则,任何对类似(+ 1 x)的代码,都建议替换成(inc x),后面的与此类似。理论上你也可以自定义规则,并提交给官方。总体上说kibit仍然是比不上findbugs的,期待未来发展的更好。
& & 我们经常需要在程序中测量某段代码的性能,或者某个函数的性能,在Java中,我们可能简单地循环调用某个方法多少次,然后利用System.currentTimeMillis()方法测量下时间。在Ruby中,一般都是用做测试,提供了更详细的报告信息。
& & 同样,在Clojure里你可以做这些事情,你仍然可以使用System.currentTimeMillis()来测量运行时间,例如:
user=&&(defn&sum1&[&&args]&(reduce&+&0&args))
#'user/sum1
user=&&(defn&sum2&[&&args]
&&&&&&&&&&&&&(loop&[rt&0
&&&&&&&&&&&&&&&&&&&&args&args]
&&&&&&&&&&&&&&&&&(if&args
&&&&&&&&&&&&&&&&&&&(recur&(+&rt&(first&args))&(next&args))
&&&&&&&&&&&&&&&&&&&rt)))
#'user/sum2
user=&&(defn&bench&[sum&n]
&&&&&&&&&(let&[start&(System/currentTimeMillis)
&&&&&&&&&&&&&&&nums&(range&0&(+&n&1))]
&&&&&&&&&&&(dotimes&[_&n]&(apply&sum&nums))
&&&&&&&&&&&(println&(-&(System/currentTimeMillis)&start))))
user=&&(bench&sum1&10000)
user=&&(bench&sum2&10000)
& & 定义两个求和函数sum1和sum2,一个是利用reduce,一个是自己写loop,然后写了个bench函数循环一定次数执行sum函数并给出执行时间,利用System.currentTimeMillis()方法。显然sum1比sum2快了一倍多。为什么更快?这不是我们的话题,有兴趣可以自己看reduce函数的实现。
& & 除了用System.currentTimeMillis()这样的java方式测量运行时间外,clojure还提供了time宏来包装这一切:
user=&&(doc&time)
-------------------------
clojure.core/time
&&Evaluates&expr&and&prints&the&time&it&took.&&Returns&the&value&of
& & time宏用的不是currentTimeMillis方法,而是JDK5引入的nanoTime方法更精确。重写bench函数:
user=&&(defn&bench&[sum&n]
&&&&&&&&&&&&&(time&(dotimes&[_&n]&(apply&sum&(range&0&(+&n&1))))))
#'user/bench
user=&&(bench&sum1&10000)
"Elapsed&time:&&msecs"
user=&&(bench&sum2&10000)
"Elapsed&time:&&msecs"
& & &尽管精度不一致,仍然可以看出来sum1比sum2快。
& & &这样的测试仍然是比较粗糙的,真正的性能测试需要考虑到JVM JIT、warm up以及gc带来的影响,例如我们可能需要预先执行函数多少次来让JVM“预热”这些代码。庆幸的是clojure世界里有一个开源库Criterium帮你自动搞定这一切,它的项目主页也在github上:
& & &首先在你的项目里添加criterium依赖:
:dependencies&[[org.clojure/clojure&"1.3.0"]
&&&&&&&&&&&&&&&&&&&&&&&&[criterium&"0.2.0"]])
& & &接下来引用criterium.core这个ns,因为criterium主要宏也叫bench,因此我们原来的bench函数不能用了,换个名字叫bench-sum:
user=&&(use&'criterium.core)
user=&&(defn&bench-sum&[sum&n]
&&&&&&&&&&&&&&(with-progress-reporting&(bench&(apply&sum&(range&0&(+&1&n)))&:verbose)))
#'user/bench-sum
& & &调用criterium的bench宏执行测试,使用with-progress-reporting宏包装测试代码并汇报测试进展,测试进展会打印在标准输出上。请注意,我这里并没有利用dotimes做循环测试,因为criterium会自己计算应该运行的循环次数,我们并不需要明确指定,测试下结果:
user=&&(bench-sum&sum1&10000)
Cleaning&JVM&allocations&
Warming&up&for&JIT&optimisations&
Estimating&execution&count&
Running&with&sample-count&60&exec-count&1417&
Checking&GC
Cleaning&JVM&allocations&
Finding&outliers&
Bootstrapping&
Checking&outlier&significance
x86_64&Mac&OS&X&10.7.3&4&cpu(s)
Java&HotSpot(TM)&64-Bit&Server&VM&20.4-b02-402
Runtime&arguments:&-pile.path=/Users/apple/programming/avos/logdashboard/test/classes&-Dtest.version=1.0.0-SNAPSHOT&-Dclojure.debug=false
Evaluation&count&&&&&&&&&&&&&:&85020
&&&&&&&&&&&&&Execution&time&mean&:&722.730169&us&&95.0%&CI:&(722.552670&us,&722.957586&us)
&&&&Execution&time&std-deviation&:&1.042966&ms&&95.0%&CI:&(1.034972&ms,&1.054015&ms)
&&&&&&&&&Execution&time&lower&ci&:&692.122089&us&&95.0%&CI:&(692.122089&us,&692.260198&us)
&&&&&&&&&Execution&time&upper&ci&:&768.239944&us&&95.0%&CI:&(768.239944&us,&768.305222&us)
Found&2&outliers&in&60&samples&(3.3333&%)
&&&&low-severe&&&&&2&(3.3333&%)
&Variance&from&outliers&:&25.4066&%&Variance&is&moderately&inflated&by&outliers
user=&&(bench-sum&sum2&10000)
Cleaning&JVM&allocations&
Warming&up&for&JIT&optimisations&
Estimating&execution&count&
Running&with&sample-count&60&exec-count&917&
Checking&GC
Cleaning&JVM&allocations&
Finding&outliers&
Bootstrapping&
Checking&outlier&significance
x86_64&Mac&OS&X&10.7.3&4&cpu(s)
Java&HotSpot(TM)&64-Bit&Server&VM&20.4-b02-402
Runtime&arguments:&-pile.path=/Users/apple/programming/avos/logdashboard/test/classes&-Dtest.version=1.0.0-SNAPSHOT&-Dclojure.debug=false
Evaluation&count&&&&&&&&&&&&&:&55020
&&&&&&&&&&&&&Execution&time&mean&:&1.070884&ms&&95.0%&CI:&(1.070587&ms,&1.071136&ms)
&&&&Execution&time&std-deviation&:&1.057659&ms&&95.0%&CI:&(1.050688&ms,&1.062877&ms)
&&&&&&&&&Execution&time&lower&ci&:&1.024195&ms&&95.0%&CI:&(1.024164&ms,&1.024195&ms)
&&&&&&&&&Execution&time&upper&ci&:&1.145664&ms&&95.0%&CI:&(1.145664&ms,&1.145741&ms)
Found&1&outliers&in&60&samples&(1.6667&%)
&&&&low-severe&&&&&1&(1.6667&%)
&Variance&from&outliers&:&19.0208&%&Variance&is&moderately&inflated&by&outliers
& & 这个报告是不是相当专业?不是搞统计还不一定读的懂。大概解读下,sample-count是取样次数,默认是60次,exec-count是测试的执行次数(不包括前期warm up和JIT在内),CI是可信区间,这里取95%,Execution time mean是平均执行时间,而lower和upper是测试过程中执行时间的最小和最大值。而outliers是这一组测试中的异常值,比如执行sum1测试发现了2组异常结果。从结果来看,sum1的平均执行时间是722微秒,而sum2的平均执行时间是1.07毫秒,因此还是sum1更快一些。
& & 总结下,如果只是在开发过程中做一些小块代码的简单测试,可以直接利用内置的time宏,如果你希望做一次比较标准的性能测试,那么就应该利用这个优秀的开源库。
& & 继续Clojure世界之旅,介绍下我今天的探索成果,使用clojure生成clojure项目的API文档。在java里,我们是利用javadoc生成API文档,各种build工具都提供了集成,例如maven和ant都提供了javadoc插件或者task。在Clojure世界里,同样有一系列工具帮助你从源码中自动化生成API文档。今天主要介绍三个工具。不过我不会介绍怎么在clojure里写doc,具体怎么做请看一些开源项目,或者直接看clojure.core的源码。
& & 首先是,使用相当简单,我们这里都假设你使用作为构建工具,在project.clj里添加codox依赖:
& :dev-dependencies&&&&[[codox&"0.5.0"]]
& & 解下执行lein doc命令即可生成文档,生成的文档放在doc目录,在浏览器里打开index.html即可观察生成的文档。我给生成的codox文档可以看,效果还是不错的。
& & 第二个要介绍的工具是,使用方法类似codox,首先还是添加依赖:
:dev-dependencies&[lein-marginalia&"0.7.0"]
&&&&执行lein deps处理依赖关系,然后执行lein&marg命令即可在docs目录生成文档,与codox不同的是marginalia只生成一个html文件,没有带js和css,但是效果也不错,可以看我给clojure-control生成的。marginalia生成的文档说明和源码左右对照,很利于阅读源码。
& &最后要介绍的就是Clojure.org自己在使用的,如果你喜欢clojure.org上的API文档格式可以采用这个工具。并且autodoc可以跟github pages结合起来,生成完整的项目文档并展示在github上。例如以clojure-control为例来介绍整个过程。首先你需要配置你的github pages,参照这个链接。
& & 第一步,仍然是在project.clj添加依赖:
:dev-dependencies&[[lein-autodoc&"0.9.0"]]
& & & &第二步,在你的.gitignore里忽略autodoc目录:
autodoc/**
& & & &将这些更改提交到github上,接下来在你的项目目录clone一份项目源码到&project&/autodoc目录:
&git&clone&git&#:&user&name&/&project&name&.git&autodoc
& & & &进入autodoc目录,执行下列命令创建一个gh-pages分支:
&$&cd&autodoc
&$&git&symbolic-ref&HEAD&refs/heads/gh-pages
&$&rm&.git/index
&$&git&clean&-fdx
& & &回到项目根目录后,执行lein autodoc命令在autodoc目录生成文档:
lein&autodoc
& & &接下来将生成的文档推送到github分支上:
&$cd autodoc&
&$&git&add&-A
&$&git&commit&-m"Documentation&update"
&$&git&push&origin&gh-pages
& & 等上几分钟,让github渲染你的文档,最终的效果看这个链接&& &&& & autodoc和marginalia都支持maven,具体使用请看他们的文档。
& & 前面一篇博客介绍了我在github上的一个分支,今天下午写了个metaq的python客户端,目前仅支持发送消息功能,不过麻雀虽小,五脏俱全,客户端和zookeeper的交互和连接管理之类都还具备,不出意外,我们会首先用上。第一次正儿八经地写python代码,写的不好的地方请尽管拍砖,多谢。& & 项目叫meta-python,仍然放在github上:& & 使用需要先安装zkpython这个库,具体安装,使用很简单,发送消息:& &&from&metamorphosis&import&Message,MessageProducer,SendResult&&&&p=MessageProducer("topic")&&&&message=Message("topic","message&body")&&&&print&p.send(message)&&&&p.close()& &&MessageProducer就是消息发送者,它的构造函数接受至少一个topic,默认的zk_servers为localhost:2181,可以通过zk_servers参数指定你的zookeeper集群:p=MessageProducer("topic",zk_servers="192.168.1.100:.1.101:2181")更多参数请直接看源码吧。一个本机的性能测试(meta和客户端都跑在我的机器上,机器是Mac MC700,osx 10.7,磁盘没有升级过):from&metamorphosis&import&Message,MessageProducerfrom&time&import&timep=MessageProducer("avos-fetch-tasks")message=Message("avos-fetch-tasks","")start=time()for&i&in&range(0,10000):&&&&sent=p.send(message)&&&&if&not&sent.success:&&&&&&&&print&"send&failed"finish=time()secs=finish-startprint&"duration:%s&seconds"&%&(secs)print&"tps:%s&msgs/second"&%&(10000/secs)p.close()&结果:duration:1.&secondstps:9&msgs/second
& & 开源的memcached Java客户端——发布1.3.6版本。
& & 主要改进如下:&
1. &为MemcachedClientBuilder添加两个新方法用于配置:
public&void&setConnectTimeout(long&connectTimeout);&&
public&void&setSanitizeKeys(boolean&sanitizeKeys);
2. &用于hibernate的XmemcachedClientFactoryd添加了connectTimeout属性,感谢网友&Boli.Jiang的贡献。
3. &添加新的枚举类型&net.rubyeye.pressionMode,用于指定Transcoder的压缩类型,默认是ZIP压缩,可选择GZIP压缩。Transcoder接口添加setCompressionMode方法。
4. &修改心跳规则,原来是在连接空闲的时候发起心跳,现在变成固定每隔5秒发起一次心跳检测连接。
5. &修改默认参数,默认禁用nagle算法,默认将批量get的合并因子下降到50。
6. &修复bug和改进,包括:、、、、、、和。
项目主页:
项目文档:
Maven依赖:
&&dependency&&&
&&&&&groupId&com.googlecode.xmemcached&/groupId&&&
&&&&&artifactId&xmemcached&/artifactId&&&
&&&&&version&1.3.6&/version&&&
&/dependency&&
& & 最后感谢所有提出issue和改进意见的朋友们。
& & 加入已经一个月多一点,很荣幸加入这个充满活力的跨国团队。去了趟北京,跟我的同事们终于当面认识了下,并且顺利举办了cn-clojure的第二次聚会。不过很悲剧的是在北京一周都在生病,哪也没去成,要见的人也没见到,要凑的饭局也没吃到,非常遗憾,希望以后再弥补。不过我暂时因为家庭的因素还在杭州远程办公,沟通都是通过gtalk和google+ hangout,很多东西对我来说都是全新的经历。远程办公有利有弊,其实我还是更喜欢能在一个办公室里工作,交流方便,只要转个椅子就好。& & 正式介绍下我们公司,大boss是youtube创始人查德•赫利(Chad Hurley)和陈士骏(Steve Chen),我们在中国的boss是前google员工/耶鲁的博士,更多关于团队成员的介绍请看,我的同事们真的很强大,我要学习的地方很多。我们做的产品是从雅虎手上买下来的,不过中国团队运作的是美味书签——。我们刚在3月1号开始做public beta,预计会在4月份的时候正式对外开放注册。我们的团队博客在。& & 我在团队里做的事情还是偏向后端,这一个月来做的事情更偏向运维之类,搞搞solr复制、mysql复制、程序监控之类,将原来只是简单了解过的东西动手做了一遍,能亲手实践的感觉不错。在此过程中要感谢锋爷和刘帅哥的帮助,再次感谢。淘宝的同事们开源了metaq和gecko,我也做了点工作,都在。几个维护的开源项目都没有太大进展,很惭愧,还被人催发新版本,能承诺的是周末发xmemcached的新版本,主要还是修bug。本来要写个clojure世界的系列文章,因为响应寥寥,也不是很有动力写下去。杂七杂八读了几本书,都没读完,这一个月杭州太冷了,雨下个不停,不过终于这一周开始晴天了,希望老天爷别再掉眼泪。& & 收拾收拾心情,整装待发,希望新的一年里能做出点不同的东西。& &&
& & 上周我在淘宝的同事开源了一个消息中间件,放在了上。我从淘蝌蚪的svn上fork了一个github的分支,放在了这里:
&1.主体工程:
&2.示例项目:
&3.Twitter storm的spout项目:
& & 主要做了一些pom文件的简化,发布1.4.0.2版本到maven central仓库,并且写了几个简单的入门文档,提供了一个完整打包可运行的下载,有兴趣的自己看github页面吧。 Wiki文档放在:
& & &客户端Maven依赖包括,可自行选择添加:
&dependency&
&&&&&groupId&com.taobao.metamorphosis&/groupId&
&&&&&artifactId&metamorphosis-client&/artifactId&
&&&&&version&1.4.0.2&/version&
&/dependency&
&dependency&
&&&&&groupId&com.taobao.metamorphosis&/groupId&
&&&&&artifactId&metamorphosis-client-extension&/artifactId&
&&&&&version&1.4.0.2&/version&
&/dependency&
&dependency&
&&&&&groupId&com.taobao.metamorphosis&/groupId&
&&&&&artifactId&storm-metamorphosis-spout&/artifactId&
&&&&&version&1.0.0&/version&
&/dependency&
& & &ps.我开通了新浪微博,有兴趣相互关注下:,你看,偏见是可以改变的。
共56页:&&&2&&&&&&&&&&

我要回帖

更多关于 jvisualvm tomcat 的文章

 

随机推荐