阅读《深入理解Java虚拟机-JVM高级特性与最佳实践》.周志明 笔记
给一个系统定位问题的时候,知识、经验是关键基础,数据是依据,工具是运用知识处理数据的手段。这里说的数据包括:运行日志、异常堆栈、GC日志、线程快照、堆转储快照等。经常使用适当的虚拟机监控和分析的工具可以加快我们分析数据、定位解决问题的速度,但在学习工具之前,也应当意识到工具永远都是知识技能的一层包装,没有什么工具是“秘密武器”,不可能学会了就包治百病。
-----引自 《深入理解Java虚拟机-JVM高级特性与最佳实践》第4章
关于几个简单的工具
工具 | 参数 | 描述 |
jps | -q | 只输出LVMID,省略主类名称 |
-m | 输出虚拟机启动进程时传递给主类main()函数的参数 | |
-l | 输出主类的全名,如果进程执行的是Jar包,输出Jar路径 | |
-v | 输出虚拟机进程启动时JVM参数(显式指定的) | |
jstat(用于监视虚拟机各种运行状态,显示本地或者远程虚机进行中的类装载信息、内存、垃圾收集、JIT编译等运行参数) | -class | 监视类装载、卸载、总空间以及类装载所耗费的时间 |
-gc | 监视Java堆状况,包括Eden区域、两个survivor区、老年代、永久代等容量、已使用空间、GC时间合计等信息 | |
-gccapacity | 监视内容与-gc基本相同,但输出主要关注Java堆各个区域使用到的最大、最小空间 | |
-gcutil | 监视内容与-gc基本相同,但输出主要关注已经使用空间占总空间百分比 | |
-gccause | 与-gcutil功能一样,但是会额外输出导致上一次GC产生的原因 | |
-gcnew | 监视新生代gc状况 | |
-gcnewcapacity | 监视内容与-gcnew基本相同,输出主要关注使用到的是最大、最小空间 | |
-gcold | 监视老年代GC状况 | |
-gcoldcapacity | 监视内容跟-gcold基本相同,输出主要关注使用到的最大、最小空间 | |
-gcpermcapacity | 输出永久代使用到的最大、最小空间 | |
-compiler | 输出JIT编译器编译过的方法、耗时等信息 | |
-printcompilation | 输出已经被JIT编译的方法 | |
jinfo | -flag <name> | to print the value of the named VM flag |
-flag [+|-]<name> | to enable or disable the named VM flag | |
-flag <name>=<value> | to set the named VM flag to the given value | |
-flags | to print Java system properties | |
-sysprops | to print Java system properties | |
<no option> | to print both of the above | |
jmap | -dump | 生成Java堆转储快照。格式为: jmap -dump[live,]format=b,file=<filename>,其中live子参数说明是否值dump出存活对象 例如:jmap -dump:live,format=b,file=dumpfile 3216 |
-finalizerinfo | 显示在F-Queue中等待Finalizer线程执行finalize方法的对象(Linux/Solaris平台有效) | |
-heap | 显示Java堆详情,如使用哪些回收器,参数配置,分代状况等(Linux/Solaris平台有效) | |
-histo | 显示堆中对象统计信息,包括类、实例数量、合计容量 | |
-permstat | 以ClassLoader为统计口径显示永久代内存状态(Linux/Solaris平台有效) | |
-F | 当虚拟机进程对-dump选项没有响应时,可使用这个选项强制生成dump快照(Linux/Solaris平台有效) | |
jhat | <dumpfilename> | 搭配jmap,分析jmap生成的堆转储快照。(简陋的功能,所以很少使用) |
jstack(用于生成虚拟机当前时刻的线程快照) | -F | 当正常输出的请求不被响应时,强制输出线程堆栈 |
-l | 除堆栈外,显示关于锁的附加信息 | |
-m | 如果调用本地方法的话,可以显示C/C++的堆栈 | |
HSDIS | HSDIS是Sun官方推荐的HotSpot虚拟机JIT编译代码的反汇编插件,它包含在虚拟机的源码中,但是没有提供编译后的程序。可在网上下载(官网已经停了,毕竟sun都没了) | |
备注: LVMID是本地虚机唯一ID,几乎所有工具都会用到这个ID,也就是说除了jps之外的命令,其他命令后边必须加这个ID,如:jinfo -flag CMSInitiatingOccupancyFraction 3216 |
另外有可视化工具JConsole和VisualVM,而JConsole过于鸡肋,就不进行学习了。主要对VisualVM进行学习了解。
VisualVM:多合一故障处理工具
VisualVM可以做到(关注什么就先来了解什么):
- 显示虚拟机进程以及进程的配置、环境信息(jps、jinfo);
- 监视应用程序的CPU、GC、堆、方法区、以及线程的信息(jstat、jstack);
- 方法级的程序运行性能分析,找出被调用最多、运行时间最长的方法(感觉这个功能好牛);
- 离线程序快照:收集程序运行时配置、线程dump、内存dump等信息建立一个快照,可以将快照发送给开发者处进行Bug反馈;
- 其他plugins的可能性…
关于插件BTrace的示例
BTrace插件的用法有:打印调用堆栈、参数、返回值等基本应用,在它的网站(官网已停)上还有使用BTrace进行性能监视、定位连接泄露和内存泄露、解决多线程竞争的问题的例子。
该插件的一个使用场景,比如线上某个程序的方法执行过程中,想要知道某些数据,但是当前日志并没有输出,那就可以使用这个插件去监控了。
被监控程序:
package jvmbtrace;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
/**
* @author by Young
* @date 2019/3/20
* @Description
*/
public class BTraceTest {
public int add(int a,int b){
return a+b;
}
public static void main(String[] args) throws IOException{
BTraceTest test = new BTraceTest();
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
for(int i=0;i<10;i++){
reader.readLine();
int a = (int) Math.round(Math.random()*1000);
int b = (int) Math.round(Math.random()*1000);
System.out.println(test.add(a,b));
}
}
}
BTrace脚本
/* BTrace Script Template */
import com.sun.btrace.annotations.*;
import static com.sun.btrace.BTraceUtils.*;
@BTrace
public class TracingScript {
/* put your code here */
@OnMethod(
clazz="jvmbtrace.BTraceTest",
method="add",
location=@Location(Kind.RETURN)
)
public static void func(@Self jvmbtrace.BTraceTest instance,int a,int b,@Return int result){
println("call stack:");
jstack();
println(strcat("param a:",str(a)));
println(strcat("param b:",str(b)));
println(strcat("result:",str(result)));
}
}