前言

基础不牢,地动山摇,菜如老哥还经常巩固自己的基本功,你就更要努力学习了。
最近博主在复习Java虚拟机,对Java虚拟机的理解又有了一个更深层次的理解,记录下一些笔记及重点摘要,让我们一起学习一下吧!

现在用不上,不代表以后就能用上,一句话,学,就行了。
学习JVM有什么意义和作用?

1、学习JVM能更深入的理解Java这门语言,能理解Java语言底层的执行过程。
2、学习JVM,为了项目上线后去排查一些程序log日志中无法呈现的问题,可以通过GC日志来排查项目问题以及进行调优。
3、能够利用一些工具,jmap, jvisualvm, jstat, jconsole等工具可以辅助你观察Java应用在运行时堆的布局情况,由此你可以通过调整JVM相关参数提高Java应用的性能。
4、学习之前面试官虐待你你会觉得很痛苦,学完之后再被虐待时你会觉得很享受。

链接附上:《干货-深入理解Java虚拟机》

JAVA虚拟机断网设置_JVM

正文

1. 监控命令

jps:

可以列出正在进行的虚拟机进程, 并显示出虚拟机执行主类(main函数所在类)名称及这些进程的本地虚拟机唯一ID(LVMID),大多数监控命令都需要LMVID来确定监控的是哪个进程,所以jps命令也是使用最为频繁的指令,对于本地虚拟机来说,LVMID和进程id(PID)是一致的。
命令格式: jps [options] [hostid]示例: jps -l参数列表:

参数

说明

-q

值输出LVMID,省略主类名称

-m

输出虚拟机进程启动时传递给主类main()的参数

-l

输出主类的全名,如果进程执行的是jar包,输出jar包路径

-v

输出虚拟机进程启动时jvm参数

jstat:

用于监视虚拟机各种运行状态信息的命令行工具,可以显示本地或者远程虚拟机进程中的类加载、内存、拉锯班车、JIT编译等运行数据,在没有界面,只提供纯文本控制台环境的服务器上,他是运行期定位虚拟机性能问题的首选工具。
命令格式:jstat [ option vmid [interval[s|ms] [count]] ]
对于VMID和LVMID需要说明一下:如果是本地虚拟机,VMID和LVMID是一致的,如果是远程虚拟机,那么VMID的格式应该是:
[protocol:] [//] lvmid[@hostname[:port]/servername] 参数interval 和count代表查询间隔和统计次数,如果省略这两个参数,说明只查询一次,假设需要250毫秒查询一次进程2764的垃圾收集情况,一共查询20次。
示例: jstat -gc 2764 250 20参数列表:

参数

说明

-class

值输出LVMID,省略主类名称

-gc

输出虚拟机进程启动时传递给主类main()的参数

-gccapacity

输出主类的全名,如果进程执行的是jar包,输出jar包路径

-gcutil

监视内容与-gc基本相同,但输出主要关注已使用的空间占总空间的百分比

-gccause

与-gcutil功能一样,但是会额外输出导致上一次GC产生的原因

-gcnew

监视新生代GC的情况

-gcnewcapacity

监视内容与-gcnew基本相同,输出主要瑞士使用到的最大最小空间

-gcold

监视老年代GC情况

-gcoldcapacity

与-gcold基本相同,输出主要关注使用到的最大、最小空间

-gcpermcapacity

输出永久代使用的最大最小空间

-compiler

输出JIT编译器编译过的方法、耗时等信息

-printcompilation

输出已经被JIT编译的方法

jinfo:

实时查看和调整虚拟机的各项参数,使用jps -v 可以查看虚拟机启动时显示指定的参数列表,但如果想要知道未被显示的系统默认值除了查资料外,就只能使用jinfi的-flag选项进行查询(JDK1.6以上的版本使用java -XX:+PrintFlagsFinal也可以)。jinfo还可以使用-sysprops选项把进程中的System.getProperties()内容打印出来。在JDK1.6之后,可以通过-flag[+|-] name 或者-flag name=value的形式来修改一部分运行期可写的参数值
命令格式: jnifo [option] pid示例: 查询CMSInitiatingOccupancyFraction参数值
jinfo -flag CMSInitiatingOccupancyFraction 1444结果

-XX:CMSInitiatingOccupancyFraction =85
jmap:

用于生成堆转储快照(一般称为heapdump或者dump文件),当然也有其他的一些手段可以获取dump文件,例如通过kill -3命令发送进程退出信号(不会影响程序的运行),也能拿到dump文件,还有一些其他的方法可以自行百度。
jmap的作用不仅仅是为了获取dump文件,它还可以查询finalize执行队列、Java堆和永久代的详细信息如空间使用率、当前用的是哪种收集器等信息。
命令格式: jmap [option] vmid示例: jmap -dump:format=b,file=eclipse.bin 3500结果

Dumping heap to C:\Users\IcyFenix\eclipse.bin ...
    Heap dump file crested

参数列表:

参数

说明

-dump

生成Java堆转储快照,格式为:-dump:[live, ]format=b,file=<filename>,其中live子参数说明是否只dump出存活的对象

-finalizerinfo

显示在F-Queue中等待Finalizer线程执行finalze方法的对象,只在Linux/Solaris平台下有效。

-heap

显示Java堆详细信息。如使用哪种回收器、参数配置、分代状况等。只在Linux/Solaris平台下有效。

-histo

显示堆中对象统计信息,包括类、实例数量、合计容量。

-permstat

以ClassLoader为统计口径显示永久代内存状态。只在Linux/Solaris平台下有效。

-F

当虚拟机进程堆-dump没有响应时,可使用这个选项强制生成dump快照。只在Linux/Solaris平台下有效。

jhat:

jhat来分析jmap生成的堆转储快照。jhat内置了一个微型的http/html服务器,生成dump文件的分析结果后,可以通过浏览器进行查看。
命令格式: jhat [dump文件]示例: jhat eclipse.bin结果:

Reading from eclipse.bin...
Server is ready.

出现Server is ready提示后,在浏览器输入http://ip:7000/就可以看到分析结果了。
分析结果默认以包为单位进行分组显示,分析内存泄漏问题主要会使用到其中的“Heap Histogram”与OQL页签的功能,前者可以找到内存中容量最大的对象,后者是标准的对象查询语言,使用类似于SQL的语法对内存中的对象进行查询统计,如果对OQL有兴趣可以自行百度。

jstack:

用于生成虚拟机当前时刻的线程快照(一般成为threaddump或者javacore文件)。线程快照就是当前虚拟机内每一条线程正在执行的方法堆栈的集合,生成线程快照的主要目的是定位线程出现长时间停顿的原因,如线程间死锁、死循环、请求外部资源导致长时间等待等都是常见原因。
线程出现停顿的时候,通过jstack来查看各个线程的调用堆栈,就可以知道没有响应的线程到底在后台做什么,或者等待什么资源。
命令格式: jstack [option] vmid示例: jstack -l 3500

<%@ page import="java.util.Map" %><%--
  Created by IntelliJ IDEA.
  User: zhanghang
  Date: 2021/6/1
  Time: 9:34
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>服务器线程信息</title>
</head>
<body>
    <pre>
        <%
            // 展示所有线程信息
            for (Map.Entry<Thread, StackTraceElement[]> stackTrace : Thread.getAllStackTraces().entrySet()) {
                Thread thread = stackTrace.getKey();
                StackTraceElement[] stacks = stackTrace.getValue();
                if (thread.equals(Thread.currentThread())){
                    continue; // 当前线程不需要展示
                }
                System.out.println("线程:"+thread.getName());
                for (StackTraceElement stack : stacks) {
                    System.out.println("\t"+stack);
                }
            }
        %>
    </pre>
</body>
</html>

2. 可视化监控工具

VisualVM:

一款可视化多合一故障处理工具,专门监控Java的虚拟机进程,其功能十分强大,相关包Oracle已经在github上面开源,网上有很多相关资源,有兴趣学习的小伙伴可以自行百度搜索(搜索近一年的)。