美文网首页
JVM调优基础——运行参数、内存分析命令、内存分析工具

JVM调优基础——运行参数、内存分析命令、内存分析工具

作者: 笔记本一号 | 来源:发表于2020-10-02 02:20 被阅读0次

    不多BB,开门见山

    -D<name>=<value>

    传入参数作为系统的参数属性,项目中可以根据这个命令传入文件路径去选择不同的配置文件,选择是开发环境配置还是测试环境配置、还是线上环境配置

    java -version
    

    我们看到上面的-server,java有两种运行模式:client和server,启动时client比server快,但是启动完成后server的比client性能更好,不同的模式默认的jvm参数和GC收集器也会不同,生产环境选择server,64位操作系统默认只有server
    HotSpot也会在启动的时候会根据自身版本以及机器的硬件性能自动选择运行模式,比如J2SE会检测主机是否有至少2个CPU和至少2GB的内存,所以到底选择什么模式不需要我们关心

    -D<name>=<value> 传入参数作为系统的参数属性
    

    我们给tomcat设置一个UTF-8属性

    后台输出日志变为了中文

    public class Test {
        public static void main(String[] args) {
            String value = System.getProperty("file.encoding");
            System.out.println(value);
        }
    }
    

    非标准参数

    -X 参数

    执行下面的命令

    java -X
    

    -Xint、-Xcomp、-Xmixed

    jvm的编译有三种模式:

    • 解释模式(interpreted mode):源程序输入到计算机后,解释程序将程序逐句翻译,翻译一句执行一句边翻译边执行
    • 编译模式(compiled mode):把源程序全部翻译成目标代码后才运行目标代码
    • 混合模式(mixed mode):将解释模式和变异模式进行混合使用,有JVM自己决定,这是JVM的默认模式,也是推荐模式
    • -Xint参数:在解释模式(interpreted mode)下,-Xint标记会强制JVM执行所有的字节码,jvm不会把代码全部编译完再运行而是一边编译一边运行,这当然会降低运行速度,通常低10倍或更多。

    • -Xcomp参数:在编译模式(compiled mode)下,-Xcomp参数与-Xint正好相反,JVM在第一次使用时会把所有的字节码编译成本地代码,把代码一次性编译完了才运行,从而带来最大程度的优化。

    • -Xmixed参数:-Xmixed是混合模式(mixed mode),将解释模式和变异模式进行混合使用,有JVM自己决定,这是JVM的默认模式,也是推荐模式

    示例 使用 -showversion可以在编译时查看版本信息

    以下使用不一的模式编译

    -XX参数

    -XX参数是主要非标准参数的高级选项,主要用于jvm的调优使用,是jvm参数学习的重点
    -XX有以下几种类型:

    • 1、boolean类型
    • 2、非boolean类型
    • 3、-Xms、-Xmx、-Xmn、-Xss

    boolean类型:Boolean类型-XX参数

    公式:-XX:+V 、-XX:-V (+表示开启,-表示关闭)
    例如:
    是否使用串行垃圾收集器:
    -XX:+UseSerialGC(开启)
    -XX:-UserSerialGC(关闭)
    
    开启打印jvm的所有内存参数:
    -XX:+PrintFlagsFinal
    

    非boolean类型:Boolean类型-XX参数

    公式: -XX: key(属性)= value(属性值)
    例如:设置元空间大小
     -XX:MetaspaceSize=21807104
    

    -Xms、-Xmx:初始化堆内存参数和最大堆内存参数(一般-Xms、-Xmx两个参数会配置相同的值,优点是:能够在Java垃圾回收机制清理完堆区后不需要重新分隔计算堆区的大小而浪费资源)

    -Xmn、-Xss:年轻代大小和每个线程的堆栈大小

    -Xms:Java虚拟机堆区内存初始内存分配的大小,等价-XX:InitialHeapSize=xxx 例如:-Xms512M 设置堆区的初始化内存为512M
    -Xmx:Java虚拟机堆区内存可被分配的最大上限,等价-XX:MaxHeapSize=xxx 例如:-Xmx512M 设置堆区的最大内存为512M
    -Xmn:年轻代大小例如:-Xmn2g 设置年轻代大小为2G
    -Xss:每个线程的堆栈大小 例如:-Xss128k 设置每个线程的堆栈大小为128k
    

    jvm参数查询及内存分析及分析工具的使用(重点内容)

    一:-XX:+Print (了解即可)

    -XX:+PrintFlagsFinal可以查看jvm的参数设置

    示例:

    cmd控制台输入:

    java -XX:+PrintFlagsFinal -version

    我们看到打印了所有的jvm运行的参数

    其中 :=xxx 代表被修改过的值

    java -XX:+PrintCommandLineFlags -version

    这个参数比较有用,只打印一部分关键参数

    二、jinfo -flags/-flag (了解即可)

    jinfo可以查看运行于jvm的进程的jvm参数设置

    1、jinfo -flag xxxx(jvm程序的进程号) 可以查看某个进程的jvm参数

    例如:
    查看服务器某个jar包的jvm参数,jar包对应的进程号是xxxx

    jinfo -flags xxxx

    先使用netstat 查询jar端口号对应的进程号xxxx,然后使用进程号jinfo -flags xxx

    netstat -anp|grep xxxx 
    

    对应的进程号是61924

    jinfo -flags 61924
    
    2、jinfo -flag xxxx xxxx(jvm程序的进程号) 可以查看某个进程的jvm参数某个参数
    jinfo -flag InitialHeapSize 61924
    

    三:jstat(了解即可)

    Jstat是JDK自带的一个轻量级小工具,可以对Java应用程序的资源和性能进行实时的命令行的监控,包括了对Heap size和垃圾回收状况的监控。
    jstat -options xxxx(jvm程序的进程号)
    可以列出当前JVM版本支持的选项,常见的有

    • -class (类加载器)
    • -compiler (JIT)
    • -gc (GC堆状态)
    • -gccapacity (各区大小)
    • -gccause (最近一次GC统计和原因)
    • -gcnew (新区统计)
    • -gcnewcapacity (新区大小)
    • -gcold (老区统计)
    • -gcoldcapacity (老区大小)
    • -gcpermcapacity (永久区大小)
    • -gcutil (GC统计汇总)
    • -printcompilation (HotSpot编译统计)

    示例:
    查看Tomcat启动的编译情况

    jstat -class 20428

    查看对应jar包的垃圾回收情况

    jstat -gcutil 61924
    监控jar包的gc回收情况,这里每1000毫秒打印一次gc回收消息 jstat -gcutil 61924 1000

    参数太多了,下面找到了CSDN的博客,里面有这个命令的各个参数介绍,自己细品吧

    https://blog.csdn.net/zhaozheng7758/article/details/8623549?biz_id=102&utm_term=jstat%E5%91%BD%E4%BB%A4%E8%AF%A6%E8%A7%A3&utm_medium=distribute.pc_search_result.none-task-blog-2allsobaiduweb~default-0-8623549&spm=1018.2118.3001.4187

    四:jmap(分析内存泄漏的基石,建议掌握)

    jmap也jdk自带的工具之一,它可以输出所有内存中对象,主要用于打印指定Java进程(或核心文件、远程调试服务器)的共享对象内存映射或堆内存细节,并且可以将JVM 中的heap以二进制输出成文本

    jmap -heap xxx(进程号) 打印heap的概要信息,GC使用的算法,heap的配置及heap内存空间使用情况
    jmap -histo[:live] xxx(进程号) 打印每个class的实例数目,内存占用,类全名信息.如果live子参数加上后,只统计活的对象数量.

    我们加上live参数,只查询存活对象的情况

    -dump:[live,]format=b,file=<filename> 使用hprof二进制形式,输出jvm的heap内容到文件, live子选项是可选的,假如指定live选项,那么只输出活的对象到文件.
    -jhat -port xxxx(端口) xxx.xxx(hprof文件) 使用这个命令然后使用浏览器访问相应端口就可以查看这个二进制文件
    手动导出

    如:jmap -dump:format=b,file=head.log 4579

    oom时自动导出:
    -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/data/log/sdc
    

    jhat -port 8999 head.log 查看文件

    然后我这边是访问这个地址就可以看到相应的jmap信息http://192.168.200.130:8999/

    下面有几个有意思的功能,

    例如:使用OQL查询字符串长度大于100的

    查出来的结果

    点进去一个,这个是我前天晚上学习的dubbo的URL

    jmap除了可以手动导出外,也可以设置自动导出

    设置参数,当内存溢出后自动导出映像文件

    • -XX:+HeapDumpOnOutOfMemoryError
    • -XX:HeapDumpPath=./ -----------------------(导出到程序的当前路径)

    写一段快速内存溢出的代码

    然后设置最大堆内存和最小堆内存设置得小一些,接着设置生产的hprof文件的生成位置

    执行程序看到内存溢出,然后打印出来了

    生产的文件

    五:MAT(分析内存泄漏的神器,建议掌握)

    MAT是一款非常强大的内存分析工具,在Eclipse中有相应的插件,同时也有单独的安装包。在进行内存分析时,只要获得了反映当前设备内存映像的hprof文件,通过MAT打开就可以直观地看到当前的内存信息。
    这个软件需要下载,各位自行百度下载
    下载后是长这样的:


    我桌面有一份hprof文件,记得用jmap生成的文件一定要hprof结尾

    利用MAT打开它:

    选择Leak Suspercts Report 这个的意思内存泄漏报告

    确定后进入这个界面default_report,这个界面帮我们列出来了几个可能有问题的类,点击下面Details »就可以查看详情

    下面的点击Overview,这个界面的有以下几个重要的选项:

    • Histogram:Histogram帮我们列出了堆内存对象信息、对象个数、对象大小
    • Dorminator Tree:Dorminator Tree这个选项帮我们列出了大对象的信息

    MAT分析实战

    我们利用这段代码生产的hprof进行实战

    default_report的分析

    打开这个hprof文件进入default_report界面,它已经帮我们列出了可疑的问题,事实证明它的怀疑是正确的

    第一段表示本地变量占用了很大的堆内存空间,第二段看出来占据这个空间的是一个LinkedList的集合
    我们点击下面的Details »进入详细分析

    点击Details »进入详细分析,如图:
    我们可以看到这里显示程序产生的大量的 LinkedList对象

    往下看我们看到这里帮我们列出了对象产生的数量,对象的类型,对象占用内存的大小

    Dorminator Tree的分析

    我们利用Dorminator Tree分析大对象,点击进入Dorminator Tree得到的列表如下:
    可以看到排在第一的线程占据了大量的空间

    点击进入查看:
    我们看到这个线程占据的哪个对象比较大,都已经从大到小帮我们排好了,我看到这个LinkedList集合占据了大量的空间

    点到这个集合中我可以看到集合中是装载的是什么对象,对象成员变量的类型,对象的占用的内存大小一目了然

    Histogram的分析

    我们利用Histogram可以查看所有对象的数量及占用的内存

    如图一目了然:

    六:jstack(查看线程堆栈信息专用,需要比较牛批的技能才看得懂)

    注意:千万不要jstack和jstat弄混了
    jstack用于打印出给定的java进程ID或core file或远程调试服务的Java进程内的线程堆栈信息
    命令格式:

    jstack [option] pid
    jstack [option] executable core
    jstack [option] [server-id@]remote-hostname-or-ip
    

    实战

    我先写一段死锁代码
    
    /**
     * 死锁
     * tzb
     */
    public class SiSuo {
        private final static Object lock1=new Object();
        private final static Object lock2=new Object();
    
        public void getLock1(){
            synchronized (lock1){
                System.out.println(Thread.currentThread().getName()+"获取到了【lock1】业务执行中..........");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName()+"等待【lock2】.................");
                getLock2();
            }
        }
    
        private void getLock2() {
            synchronized (lock2){
                System.out.println(Thread.currentThread().getName()+"获取到了【lock2】业务执行中..........");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName()+"等待【lock1】.................");
                getLock1();
            }
        }
    
        public static void main(String[] args) {
            final SiSuo siSuo=new SiSuo();
            new Thread(()->{
               while (true){
                  siSuo.getLock1();
               }
            }).start();
            new Thread(()->{
                while (true){
                    siSuo.getLock2();
                }
            }).start();
        }
    }
    

    把代码考到服务器上,用最牛批的javac编译

    出现了SiSuo的进程

    注意的地方,我已经全部全出来了,我们看到线程0和线程1都BLOCKED了,然后他们都在waiting着对方的锁,你在看着图细细品

    上图往下拉,deadlock,waiting。各种复杂的单词,信息线程的信息比较全,你细品

    七:jvisualvm(究极武器,前面的工具能做的它都能做)

    JVisualVM是JDK自带的一款全能型性能监控和故障分析工具,包括对CPU使用、JVM堆内存消耗、线程、类加载的实时监控,内存dump文件分析,垃圾回收运行情况的可视化分析等,对故障排查和性能调优很有帮助。在windows中安装JDK后,VisualVM位于%JAVA_HOME%/bin/下,直接执行jvisualvm.exe即可

    在jdk的bin目录下

    双击打开
    里面有本机JVM参数信息,还要idea的,Tomcat,有监视,线程,概述,抽样器的选项

    监视选项

    监视选项中信息,有很多如下图

    image.png
    还有其他选项,百度自己研究吧,直接略过了

    远程连接Tomcat

    连接远程的Tomcat要在catalina.sh 中加上这个配置

    CATALINA_OPTS="$CATALINA_OPTS -Dcom.sun.management.jmxremote -Djava.rmi.server.hostname=192.168.200.130 -Dcom.sun.management.jmxremote.port=8111 -Dcom.sun.management.jmxremote.rmi.port=8111 -Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.management.jmxremote.authenticate=false"
    

    企业级监控工具:prometheus(普罗米修斯)+Grafana

    现在云上应用大部分使用的是prometheus+Grafana
    参考:https://blog.csdn.net/duysh/article/details/104247956

    prometheus

    引入依赖:

     <dependency>
              <groupId>io.micrometer</groupId>
             <artifactId>micrometer-registry-prometheus</artifactId>
    </dependency>
    <dependency>
              <groupId>org.springframework.boot</groupId>
             <artifactId>spring-boot-starter-actuator</artifactId>
    </dependency>
    

    下载prometheus
    https://prometheus.io/download/
    下载安装好后配置项目的yml

    management:
      endpoints:
        web:
          exposure:
            include: 'info,health,prometheus'
      endpoint:
        prometheus:
          enabled: true
        metrics:
          enabled: true
      metrics:
        tags:
          application: ${spring.application.name}
        export:
          prometheus:
            enabled: true
    

    配置prometheus的yml

    # my global config
    global:
      scrape_interval:     15s # Set the scrape interval to every 15 seconds. Default is every 1 minute.
      evaluation_interval: 15s # Evaluate rules every 15 seconds. The default is every 1 minute.
      # scrape_timeout is set to the global default (10s).
    
    # Alertmanager configuration
    alerting:
      alertmanagers:
        - static_configs:
            - targets:
              # - alertmanager:9093
    
    # Load rules once and periodically evaluate them according to the global 'evaluation_interval'.
    rule_files:
    # - "first_rules.yml"
    # - "second_rules.yml"
    
    # A scrape configuration containing exactly one endpoint to scrape:
    # Here it's Prometheus itself.
    scrape_configs:
      # The job name is added as a label `job=<job_name>` to any timeseries scraped from this config.
      - job_name: 'prometheus'
    
        # metrics_path defaults to '/metrics'
        # scheme defaults to 'http'.
    
        static_configs:
          - targets: ['localhost:9090']
    
      - job_name: 'test-pro'
        scrape_interval: 5s
        metrics_path: '/actuator/prometheus'
        static_configs:
          - targets: [ 'localhost:19090' ]
    

    访问 localhost:9090


    下载安装Grafana
    https://grafana.com/grafana/download
    如何配置整合prometheus请参考:https://blog.csdn.net/duysh/article/details/104247956
    Grafana的端口是3000,默认用户名和密码:admin/admin
    Grafana的监控,非常的全面:

    相关文章

      网友评论

          本文标题:JVM调优基础——运行参数、内存分析命令、内存分析工具

          本文链接:https://www.haomeiwen.com/subject/zeimuktx.html