JVM常用命令(九)
前面东西说完后,现在可以说一些和我们平时进行性能调优相关的东西了,那怎么看和我们JVM性能调优相关的东西呢,其实这对我们开发来说是一个比较头痛的问题,其实我们JDK官网给了一些我们相关的指令,我们可以用这些命令去排查当前JAVA中当前有多少个进程、可以知道我们内存空间中他是一个什么样的结构、哪些对象占用的比较大、哪些对象占用的比较小、还有查看我们的类加载信息、查看GC信息等。
官网:https://docs.oracle.com/javase/8/docs/technotes/guides/troubleshoot/index.html
一、jps
我们不管查什么信息,首先第一个针对的对象肯定是java的进程而言的,所以第一个要说的命令就是查看当前系统的java的进程。在演示之前先随便打开一个自己的java项目,这个只要是开发人员都会有,我就不上传DEMO了。启动项目后然后打开本地的命令行。
输入命令jps后可以看到我启动的项目java进程和进程号PID

接下来所有的操作都可以以这个进程号进行开展
二、jinfo
(1)实时查看和调整JVM配置参数The jinfo command prints Java configuration information for a specified Java process or core file or a remote debug server.(2)查看用法 jinfo -flflag name PID 查看某个java进程的name属性的值
The configuration information includes Java system properties and Java Virtual Machine (JVM) command-line flags.
jinfo -flag MaxHeapSize PID
jinfo -flag UseG1GC PID #查看是否用到了G1,有'-'号表示没有用到

jinfo -flag [+|-] PID jinfo -flag(4)查看曾经赋过值的一些参数= PID
jinfo -flags PID #查看全部

三、jstat
查看进程的类的信息和GC的信息
(1)查看虚拟机性能统计信息The jstat command displays performance statistics for an instrumented Java HotSpot VM.(2)查看类装载信息
The target JVM is identified by its virtual machine identifier, or vmid option.
jstat -class PID 1000 10 查看某个java进程的类装载信息,每1000毫秒输出一次,共输出10次

可以通过上面可以看到有多少个类被装载进来了,也可以看到有多少个类被卸载了
(3)查看垃圾收集信息jstat -gc PID 1000 10

可以看到s0/s1什么一堆信息
四、jstack
前面我们看到了进程、类和gc的信息了,接下来要看的就是要看线程的信息了。
(1)查看线程堆栈信息The jstack command prints Java stack traces of Java threads for a specified Java process, core file, or remote debug server.
(2)用法
jstack PID

这里面有很多线程,有业务线程和GC线程,查到这些有什么用呢,其实这个其实用处很多,比喻排查死锁情况
(4)排查死锁案例public class DeadLockDemo { public static void main(String[] args) { DeadLock d1=new DeadLock(true); DeadLock d2=new DeadLock(false); Thread t1=new Thread(d1); Thread t2=new Thread(d2); t1.start(); t2.start(); } } //定义锁对象 class MyLock{ public static Object obj1=new Object(); public static Object obj2=new Object(); } //死锁代码 class DeadLock implements Runnable{ private boolean flag; DeadLock(boolean flag){ this.flag=flag; } public void run() { if(flag) { while(true) { synchronized(MyLock.obj1) { System.out.println(Thread.currentThread().getName()+"----if 获得obj1锁"); synchronized(MyLock.obj2) { System.out.println(Thread.currentThread().getName()+"--- -if获得obj2锁"); } } } }else { while(true){ synchronized(MyLock.obj2) { System.out.println(Thread.currentThread().getName()+"----否则 获得obj2锁"); synchronized(MyLock.obj1) { System.out.println(Thread.currentThread().getName()+"--- -否则获得obj1锁"); } } } } } }

jsack分析


会发现两个线程发生了死锁
五、jmap
上面这些内容看完后其实还有一个很重要的东西没看,那就是运行时数据区堆的运行情况
(1)生成堆转储快照The jmap command prints shared object memory maps or heap memory details of a specified process, core file, or remote debug server.
(2)打印出堆内存相关信息
jmap -heap PID

jmap -dump:format=b,file=heap.hprof PID

-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=heap.hprof(5)关于dump下来的文件可以结合工具来分析,这块后面再说。
六、执行引擎
Person.java源码文件是Java这门高级开发语言,对程序员友好,方便我们开发。javac编译器将Person.java源码文件编译成class文件[我们把这里的编译称为前期编译],交给JVM运行,因为JVM只能认识class字节码文件。同时在不同的操作系统上安装对应版本的JDK,里面包含了各自屏蔽操作系统底层细节的JVM,这样同一份class文件就能运行在不同的操作系统平台之上,得益于JVM。这也是Write Once,Run Anywhere的原因所在。 最终JVM需要把字节码指令转换为机器码,可以理解为是0101这样的机器语言,这样才能运行在不同的机器上,那么由字节码转变为机器码是谁来做的呢?说白了就是谁来执行这些字节码指令的呢?这就是执行引擎。
6.1、解释执行
Interpreter,解释器逐条把字节码翻译成机器码并执行,跨平台的保证。刚开始执行引擎只采用了解释执行的,但是后来发现某些方法或者代码块被调用执行的特别频繁时,就会把这些代码认定为“热点代码”。6.2 即时编译器
Just-In-Time compilation(JIT),即时编译器先将字节码编译成对应平台的可执行文件,运行速度快。即时编译器会把这些热点代码编译成与本地平台关联的机器码,并且进行各层次的优化,保存到内存中。6.3 JVM采用哪种方式
JVM采取的是混合模式,也就是解释+编译的方式,对于大部分不常用的代码,不需要浪费时间将其编译成机器码,只需要用到的时候再以解释的方式运行;对于小部分的热点代码,可以采取编译的方式,追求更高的运行效率。6.4 即使编译器类型
(1)HotSpot虚拟机里面内置了两个JIT:C1和C2- C1也称为Client Compiler,适用于执行时间短或者对启动性能有要求的程序
- C2也称为Server Compiler,适用于执行时间长或者对峰值性能有要求的程序