文章目录

  • 命令行工具
  • jps(JVM process Status Tool)
  • jps失效问题
  • jstat(JVM statistics Monitoring Tool)
  • jinfo
  • jmap
  • jhat
  • OQL
  • jstack
  • 可视化工具
  • jhsdb
  • jconsole
  • 空循环
  • 活锁
  • 死锁
  • jvisualvm
  • 插件下载
  • 生成堆快照
  • 保存以及导入
  • 分析CPU和内存
  • BTrace动态日志跟踪
  • 代码清单
  • JMC
  • HotSpot虚拟机插件及工具
  • HSDIS:JIT生成代码反汇编


给一个系统定位问题的时候,知识、经验是关键基础,数据是依据,工具是运用知识处理数据的手段

虚拟机监控平台勾选不了 ha虚拟机监控错误_虚拟机监控平台勾选不了


具体功能都在tools.jar中

虚拟机监控平台勾选不了 ha虚拟机监控错误_jar_02


虚拟机监控平台勾选不了 ha虚拟机监控错误_数据_03

命令行工具

虚拟机监控平台勾选不了 ha虚拟机监控错误_java_04

jps(JVM process Status Tool)

虚拟机进程状况工具
		列出正在运行的虚拟机进程,
		显示虚拟机执行主类(Main Class,main()函数所在类)的名称,
		进程在本地虚拟机的唯一ID(LVMID local Virtual Machine Identifier)
		通过RMI协议查询开启RMI服务的远程虚拟机进程状态
		LVMID与操作系统的进程id(PID,Process Identifier)一致

虚拟机监控平台勾选不了 ha虚拟机监控错误_jar_05


虚拟机监控平台勾选不了 ha虚拟机监控错误_java_06

jps失效问题

java程序启动后,会在目录/tmp/hsperfdata_{userName}/下生成几个文件,文件名就是java进程的pid,因此jps列出进程id就是把这个目录下的文件名列一下而已,至于系统参数,则是读取文件中的内容。

我们来思考下:如果由于磁盘满了,无法创建这些文件,或者用户对这些文件没哟读的权限。又或者因为某种原因这些文件或者目录被清除,出现以上这些情况,就会导致jps命令失效。

如果jps命令失效,而我们又要获取pid,还可以使用以下两种方法:

1、top | grep java
2、ps -ef |grep java

jstat(JVM statistics Monitoring Tool)

监视虚拟机各种运行状态信息工具
	显示本地或远程虚拟机进程中的类装载,内存,垃圾收集,JIT编译等运行数据
命令格式
jstat[option vimd [interval[s|ms][count]]]
本地虚拟机进程vmid和lvmid一致
远程虚拟机进程,vmid格式为[protocol:][//]lvmid[@hostname[:port]/servername]
interval与count表示:查询间隔和次数,省略默认查询一次
opt:用户希望查询的虚拟机信息,类装载,垃圾收集,运行期编译状况

虚拟机监控平台勾选不了 ha虚拟机监控错误_数据_07


虚拟机监控平台勾选不了 ha虚拟机监控错误_jar_08


S0和S1表示2个Survivor区

O:老年代

P:永久代

YGC:新生代GC次数

FGC:full GC次数

FGCT:full GC总耗时

GCT:GC总耗时

jinfo

java配置信息工具
实时查看和调整虚拟机的各项参数
jps -v:查看虚拟机启动时显示指定的参数列表
-flag:未被显式指定的参数的系统默认值(1.6及以上,使用java -XX:+PrintFlagsFinal也可以)
-sysprops:打印虚拟机进程的System.getProperties()
JDK1.6之后:-flag [+|-]name或者 -flag name=value修改一部分运行期间可写的虚拟机参数值
命令
jinfo [option] pid

虚拟机监控平台勾选不了 ha虚拟机监控错误_java_09

虚拟机监控平台勾选不了 ha虚拟机监控错误_数据_10

jmap

java内存映像工具
用于生成堆转换快照(一般称之为heapdump/dump文件),查询finalize执行队列,java堆和永久代的详细信息(如空间使用率,当前用的是那种收集器等)
也可以使用-XX:+HeapDumpOnOutOfMemoryError参数:虚拟机在OOM异常出现之后自动生成dump文件
-XX:+HeapDumpOnCtrlBreak:可以使用Ctrl+Break键让虚拟机生成dump文件,
Linux可以使用Kill -3发出进程退出信号,生成dump文件
-dump/-histo只能在window使用,其余选项,只能在linux/solaris使用
命令格式
jmap [option] vmid

虚拟机监控平台勾选不了 ha虚拟机监控错误_虚拟机监控平台勾选不了_11

jmap -dump:format=b,file=a 7664

虚拟机监控平台勾选不了 ha虚拟机监控错误_java_12

jhat

分析jmap生成的堆转储快照
内置卫星的HTTP/HTML服务器,生成的dump文件分析结果后可以在浏览器中查看,分析结果默认包单位分组
http://localhost:7000/
局限,分析耗时且消耗硬件资源,功能过于简陋
命令格式
jhat dump文件路径

虚拟机监控平台勾选不了 ha虚拟机监控错误_虚拟机监控平台勾选不了_13


虚拟机监控平台勾选不了 ha虚拟机监控错误_数据_14

OQL

类似于SQL的查询语言,用于查询Java堆。

虚拟机监控平台勾选不了 ha虚拟机监控错误_jar_15


虚拟机监控平台勾选不了 ha虚拟机监控错误_数据_16

jstack

java堆栈跟踪工具
生成虚拟机当前时刻的线程快照(一般称之为threaddump/javacore文件)
线程快照就是当前虚拟机内每一条线程正在执行的堆栈的集合
线程快照主要目的定位线程出现长时间停顿的原因(如线程间死锁,死循环..)
命令格式
jstack [option] vmid
java.lang.Thread#getAllStackTraces()用于获取虚拟机中所有线程的StackTraceElement对象,可以完成jstack大部分功能

虚拟机监控平台勾选不了 ha虚拟机监控错误_jar_17

虚拟机监控平台勾选不了 ha虚拟机监控错误_数据_18

可视化工具

jhsdb

虚拟机监控平台勾选不了 ha虚拟机监控错误_虚拟机监控平台勾选不了_19

/**
 * -Xmx10m -XX:+UseSerialGC -XX:-UseCompressedOops
 * 由于JHSDB本身对压缩指针的支持存在很多缺陷,建议用64位系统的读者在实验时禁用压缩指针(-XX:-UseCompressedOops)
 */
public class JHSDB_TestCase {
    static class Test {
        static ObjectHolder staticObj = new ObjectHolder();//方法区,元空间,对象存储堆中
        ObjectHolder instanceObj = new ObjectHolder();   //堆中

        void foo() {
            ObjectHolder localObj = new ObjectHolder();//foo局部变量表栈中存索引,对象存储堆中
            System.out.println("done"); // 这里设一个断点
        }

    }
    private static class ObjectHolder {
    }
    public static void main(String[] args) {
        Test test = new JHSDB_TestCase.Test();
        test.foo();
    }
}

在java9之前,JAVA_HOME/lib目录下有个sa-jdi.jar,可以通过如上命令启动HSDB(图形界面)及CLHSDB(命令行)
sa-jdi.jar中的sa的全称为Serviceability Agent,它之前是sun公司提供的一个用于协助调试HotSpot的组件,而HSDB便是使用Serviceability Agent来实现的
HSDB就是HotSpot Debugger的简称,由于Serviceability Agent在使用的时候会先attach进程,然后暂停进程进行snapshot,最后deattach进程(进程恢复运行),所以在使用HSDB时要注意

启动图形页面
java -cp $JAVA_HOME/lib/sa-jdi.jar sun.jvm.hotspot.HSDB 
启动命令行
java -cp $JAVA_HOME/lib/sa-jdi.jar sun.jvm.hotspot.CLHSDB

虚拟机监控平台勾选不了 ha虚拟机监控错误_数据_20

虚拟机监控平台勾选不了 ha虚拟机监控错误_数据_21


使用scanoops命令在Java堆的新生代(从Eden起始地址到To Survivor结束地址)范围内查找ObjectHolder的实例

命令行:scanoops 0x04a00000 0x04f50000 C_JConsoleAndVisualVM.JHSDB_TestCase$ObjectHolder

虚拟机监控平台勾选不了 ha虚拟机监控错误_jar_22


发现有三个ObjectHolder对象,三个对象分别存储在堆中,

staticObj,instanceObj存储堆中,localObj存储局部变量表(栈中)通过Inspector查看存放对象信息

可以查看到对象头和指向对象元数据的指针,里面包括了Java类型的名字、继承关系、实现接口关系,字段信息、方法信息、运行时常量池的指针、内嵌的虚方法表(vtable)以及接口方法表(itable)等。

虚拟机监控平台勾选不了 ha虚拟机监控错误_数据_23

revptrs 0x04c1fd50 0x04c1d1c0

revptrs 0x04c1fd68 0x04c1fd58

revptrs 0x04c1fd70

虚拟机监控平台勾选不了 ha虚拟机监控错误_java_24


可以看到0x04c1fd50由0x04c1d1c0引用

下图也看得出来

虚拟机监控平台勾选不了 ha虚拟机监控错误_数据_25


虚拟机监控平台勾选不了 ha虚拟机监控错误_数据_26


当查看0x04c1fd70引用的时候发现null,也就是说不在堆中,刚测的2个在堆中的对象分别是staticObj,instanceObj,也就是说localObj的引用不在堆,它的引用在局部变量表栈中,从栈中查找就行了

虚拟机监控平台勾选不了 ha虚拟机监控错误_java_27


jdk8这里显示的是局部变量没有找到引用,无法测试了,正常的显示应该是在

虚拟机监控平台勾选不了 ha虚拟机监控错误_jar_28

jconsole

虚拟机监控平台勾选不了 ha虚拟机监控错误_虚拟机监控平台勾选不了_29

虚拟机监控平台勾选不了 ha虚拟机监控错误_数据_30

空循环

可看见线程处于RUNNABLE运行状态,这种情况会一直占用CPU

虚拟机监控平台勾选不了 ha虚拟机监控错误_java_31

活锁

虚拟机监控平台勾选不了 ha虚拟机监控错误_数据_32

死锁

虚拟机监控平台勾选不了 ha虚拟机监控错误_jar_33


虚拟机监控平台勾选不了 ha虚拟机监控错误_jar_34


虚拟机监控平台勾选不了 ha虚拟机监控错误_数据_35

jvisualvm

插件下载

点击工具->插件

虚拟机监控平台勾选不了 ha虚拟机监控错误_数据_36


下载插件会jdk1.6\lib\visualvm放在此目录下

生成堆快照

虚拟机监控平台勾选不了 ha虚拟机监控错误_java_37

保存以及导入
dump文件保存,创建dump文件后,右键-->另存为,不这样的话关闭visualVM时默认当做临时文件处理掉
导入:点击window视图-->文件-->装入-->选择文件

分析CPU和内存

虚拟机监控平台勾选不了 ha虚拟机监控错误_数据_38


注意:jdk1.5之后,在client模式下的虚拟机加入并且自动开启了类共享,这是一个在多虚拟机进程中共享rt.jar中的类数据以提高加载速度和节省内存的优化

VisualVM的Profiler功能可能会因为类共享而导致被监视的应用程序崩溃,建立关闭类共享优化-Xshare:off

BTrace动态日志跟踪

在不停止目标程序运行的前提下,通过HotSpot虚拟机的HotSwap技术动态加入原本并不存在的调试代码。

范围使用:排除错误,如方法参数,返回值

1:下载BTrace插件

2: 点击应用程序面板右键,点击Trace Application

虚拟机监控平台勾选不了 ha虚拟机监控错误_java_39

虚拟机监控平台勾选不了 ha虚拟机监控错误_虚拟机监控平台勾选不了_40

代码清单

public class D_testVisualVM {
	public int add(int a, int b) {
		return a + b;
	}

	public static void main(String[] args) throws Exception {
		D_testVisualVM b_Trace = new D_testVisualVM();
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		for (int i = 0; i < 10; i++) {
			br.readLine();
			int a = (int) (Math.random() * 1000);
			int b = (int) (Math.random() * 1000);
			System.out.println(b_Trace.add(a, b));
		}
	}
}

日志代码

import com.sun.btrace.annotations.*;  
import static com.sun.btrace.BTraceUtils.*;  
@BTrace  
public class TracingScript {  
   @OnMethod(  
      clazz="C_JConsoleAndVisualVM.D_testVisualVM",  
      method="add",  
      location=@Location(Kind.RETURN)  
   )  
   public static void func(@Self C_JConsoleAndVisualVM.D_testVisualVM instance,int a,int b ,@Return int result){  
 
    jstack();
    println(strcat("方法参数A:",str(a)));
        println(strcat("方法参数B:",str(b)));
            println(strcat("方法结果:",str(result)));
   }  
}

在运行期间动态织入日志代码,跟idea,debug时可以动态设置步入条件语句,还有Fiddler抓websocket织入语句一样.

JMC

Java Mission Control:可持续在线的监控工具

虚拟机监控平台勾选不了 ha虚拟机监控错误_java_41


JFR的基本工作逻辑是开启一系列事件的录制动作,当某个事件发生时,这个事件的所有上下文

数据将会以循环日志的形式被保存至内存或者指定的某个文件当中,循环日志相当于数据流被保留在

一个环形缓存中,所以只有最近发生的事件的数据才是可用的。JMC从虚拟机内存或者文件中读取并

展示这些事件数据,并通过这些数据进行性能分析。

HotSpot虚拟机插件及工具

·Ideal Graph Visualizer:用于可视化展示C2即时编译器是如何将字节码转化为理想图,然后转化为
机器码的。
·Client Compiler Visualizer[1]:用于查看C1即时编译器生成高级中间表示(HIR),转换成低级中
间表示(LIR)和做物理寄存器分配的过程。
·MakeDeps:帮助处理HotSpot的编译依赖的工具。
·Project Creator:帮忙生成Visual Studio的.project文件的工具。
·LogCompilation:将-XX:+LogCompilation输出的日志整理成更容易阅读的格式的工具。
·HSDIS:即时编译器的反汇编插件。

HSDIS:JIT生成代码反汇编

让HotSpot的-XX:+PrintAssembly指令调用它来把即时编译器动态生成的本
地代码还原为汇编代码输出,同时还会自动产生大量非常有价值的注释

使用的是SlowDebug或者FastDebug版的HotSpot,那可以直接通
过-XX:+PrintAssembly指令使用的插件;如果使用的是Product版的HotSpot,则还要额外加入一
个-XX:+UnlockDiagnosticVMOptions参数才可以工作

命令
java -XX:+PrintAssembly -Xcomp -XX:CompileCommand=dontinline,*Bar.sum -XX:Compile-Command=compileonly,*Ba
参数-Xcomp是让虚拟机以编译模式执行代码,这样不需要执行足够次数来预热就能触发即
时编译。两个-XX:CompileCommand的意思是让编译器不要内联sum()并且只编译sum(),-XX:
+PrintAssembly就是输出反汇编内容

当汇编代码量过大的时候,可使用JITWatch

java -XX:+PrintAssembly -XX:+UnlockDiagnosticVMOptions -Xcomp -XX:CompileCommand=dontinline,*Bar.sum -XX:Compile-Command=compileonly,*B