JVM知识体系学习七:了解JVM常用命令行参数、GC日志详解、调优三大方面(JVM规划和预调优、优化JVM环境、JVM运行出现的各种问题)

文章目录

  • 前言
  • 一、了解JVM常用命令行参数
    • 1、命令行参数概述
    • 2、常用命令
    • 3、通过案例学命令行参数(Linux)
    • 4、区分概念
  • 二、GC日志详解
    • 1、打印详细日志
    • 2、日志描述
    • 3、解析案例
  • 三、调优前的基础概念
  • 四、调优是什么?
    • 1、调优1:JVM规划和预调优
      • a、涨知识时刻
      • b、概述
      • c、案例1
      • d、案例2:
    • 2、调优2:优化JVM运行环境(慢、卡顿)
      • a、三个问题
      • b、问题1
      • c、问题2
      • d、问题3
      • e、如何监控JVM
    • 3、调优3:解决JVM运行出现的各种问题*****
      • a、风险评控-测试
        • i、代码
        • ii、定位线程占用CPU高的位置
        • iii、作业:1:写一个死锁程序,用jstack观察 2 :写一个程序,一个线程持有锁不释放,其他线程等待
      • b、jconsole远程连接(图形监控)
      • c、jvisualvm远程连接(了解即可)
      • d、jprofiler (收费)
      • e、阿里的arthas在线排查工具

前言

一、了解JVM常用命令行参数

JVM调优第一步,了解JVM常用命令行参数

1、命令行参数概述

  • JVM的命令行参数参考(只有8版本):https://docs.oracle.com/javase/8/docs/technotes/tools/unix/java.html
  • HotSpot参数分类

    标准: - 开头,所有的HotSpot都支持
    非标准:-X 开头,特定版本HotSpot支持特定命令
    不稳定:-XX 开头,下个版本可能取消

2、常用命令

  1. java -version:查看java 的版本
  2. java -X:查看java 非标准的、特定HotSpot的特定命令
  3. java -XX:+PrintFlagsFinal -version | grep CMS。(Linux过滤查找)
    • PrintFlagsFinal :查看jvm默认参数
  4. -XX:+PrintFlagsInitial 是打印所有的默认参数设置
  5. -XX:+PrintFlagsFinal 是打印最终值,如果某个默认值被新值覆盖,显示新值
  6. -XX:+PrintCommandLineFlags 是打印命令行参数。

3、通过案例学命令行参数(Linux)

package com.mashibing.jvm.c5_gc;

//-XX:+PrintGCDetails -XX:+UseConcMarkSweepGC -XX:+PrintFlagsFinal -XX:+PrintVMOptions -
public class T01_HelloGC {
    public static void main(String[] args) {

        for(int i=0; i<10000; i++) {
            byte[] b = new byte[1024 * 1024];
        }
    }
}
  1. -XX:+PrintGCDetails:查看JVM详细信息
  2. -XX:+UseConcMarkSweepGC = ParNew + CMS + Serial Old
  3. -XX:+PrintFlagsFinal :最终参数值
  4. -XX:+PrintVMOptions
  5. java -XX:+PrintCommandLineFlags HelloGC : HelloGC是测试类
  6. java -Xmn10M -Xms40M -Xmx60M -XX:+PrintCommandLineFlags -XX:+PrintGC T01_HelloGC
    • -Xmn10M:n是new,新生代的大小
    • -Xms40M:设置 heap 初始化大小
    • -Xmx60M:设置 heap 最大值 (与初始值一般设置同大小值)
    • -XX:+PrintCommandLineFlags:打印命令行参数
    • -XX:+PrintGC:打印GC回收信息
  7. 其他几个详细信息
    • -XX:+PrintGCDetails :GC详细信息
    • -XX:+PrintGCTimeStamps:GC时间
    • -XX:+PrintGCCauses:GC原因


8. java -XX:+UseConcMarkSweepGC -XX:+PrintCommandLineFlags HelloGC




9. java -XX:+PrintFlagsInitial 默认参数值
10. java -XX:+PrintFlagsFinal 最终参数值
11. java -XX:+PrintFlagsFinal | grep xxx 找到对应的参数
* java -XX:+PrintFlagsFinal -version |grep GC:找与GC相关的命令行参数

4、区分概念

内存泄漏memory leak,内存溢出out of memory

  • 问题:

    • 1)有对象应该是要被标记成垃圾回收的,但是因为还有引用指向该对象,从而该对象一直没被清除,实际已经没有代码块要使用了。存在这种对象时就可以说是内存泄漏了嘛?
    • 2)同时是不是内存泄漏的对象一多了之后,就会产生内存溢出的问题?
    • 3)如果一个对象new的时候,就比堆内存老年代都要大,是不是就直接报内存溢出?
  • 解释:

    • 在Java中,内存泄漏就是存在一些被分配的对象,这些对象有下面两个特点,首先,这些对象是可达的,即在有向图中,存在通路可以与其相连;其次,这些对象是无用的,即程序以后不会再使用这些对象。如果对象满足这两个条件,这些对象就可以判定为Java中的内存泄漏,这些对象不会被GC所回收,然而它却占用内存。

    • 内存泄漏得多了,就会发现要分配内存的时候没有地方分配了,也就是内存溢出了

二、GC日志详解

1、打印详细日志

每种垃圾回收器的日志格式是不同的!
PS日志格式

// 打印GC的详细信息
java -Xmn10M -Xms40M -Xmx60M -XX:+PrintCommandLineFlags -XX:PrintGCDetails T01_HelloGC


2、日志描述

JVM知识体系学习七:了解JVM常用命令行参数、GC日志详解、调优三大方面(JVM规划和预调优、优化JVM环境、JVM运行出现的各种问题)_第1张图片

  • 命令 time ls,如下所示
    1. 意思就是 time 命令执行的情况 在 user 态、sys态、real(总)态,各占用多长时间。
      JVM知识体系学习七:了解JVM常用命令行参数、GC日志详解、调优三大方面(JVM规划和预调优、优化JVM环境、JVM运行出现的各种问题)_第2张图片

3、解析案例

就是对2.1中的打印的信息,做详细的解刨

heap dump信息解刨如下:

eden space 5632K, 94% used [0x00000000ff980000,0x00000000ffeb3e28,0x00000000fff00000)
后面的内存地址指的是,起始地址,使用空间结束地址,整体空间结束地址
JVM知识体系学习七:了解JVM常用命令行参数、GC日志详解、调优三大方面(JVM规划和预调优、优化JVM环境、JVM运行出现的各种问题)_第3张图片

三、调优前的基础概念

  • 两个概念

    1. 吞吐量:用户代码时间 /(用户代码执行时间 + 垃圾回收时间)
    2. 响应时间STW(stop the world) 越短,响应时间越好
  • 所谓调优,首先确定,追求啥?吞吐量优先,还是响应时间优先?还是在满足一定的响应时间的情况下,要求达到多大的吞吐量

  • 问题:

    • 如果是科学计算:吞吐量 优先。
    • 如果是数据挖掘,thrput(吞吐量)优先。
  • 吞吐量优先

    • 一般选:(PS + PO)版本
  • 响应时间优先(网站类型)

    • 一般选 GUI API (1.8版本选择 G1)

四、调优是什么?

  1. 根据需求进行JVM规划和预调优
  2. 优化运行JVM运行环境(慢,卡顿)
  3. 解决JVM运行过程中出现的各种问题(OOM是其中一部分)

从下面三个章节开始细讲:

1、调优1:JVM规划和预调优

a、涨知识时刻

QPS、TPS、PPS(Per Second)
淘宝20年最多并发 54W
JVM知识体系学习七:了解JVM常用命令行参数、GC日志详解、调优三大方面(JVM规划和预调优、优化JVM环境、JVM运行出现的各种问题)_第4张图片

12306号称最多并发,上百万并发。
面试官问:你们服务最大的并发量是多少?

b、概述

  • 调优,从业务场景开始,没有业务场景的调优都是耍流氓
  • 无监控(压力测试,能看到结果),不调优
  • 步骤:
    1. 熟悉业务场景(没有最好的垃圾回收器,只有最合适的垃圾回收器)(以下两个更看重哪个)
      1. 响应时间、停顿时间 [CMS G1 ZGC] (需要给用户作响应)
      2. 吞吐量 = 用户时间 /( 用户时间 + GC时间) [PS]
    2. 选择回收器组合
    3. 计算内存需求(经验值 1.5G 16G)
    4. 选定CPU(越高越好)
    5. 设定年代大小、升级年龄
    6. 设定日志参数
      1. 生产环境产出的日志参数:-Xloggc:/opt/xxx/logs/xxx-xxx-gc-%t.log -XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=5 -XX:GCLogFileSize=20M -XX:+PrintGCDetails -XX:+PrintGCDateStamps -XX:+PrintGCCause
        • -Xloggc:/opt/xxx/logs/xxx-xxx-gc-%t.log 指定文件名和路径
        • -XX:+UseGCLogFileRotation:GC文件循环使用
        • -XX:NumberOfGCLogFiles=5:GC日志文件为5个
        • -XX:GCLogFileSize=20M:每个GC文件大小为20M
        • -XX:+PrintGCDetails:打印GC详细信息
        • -XX:+PrintGCDateStamps:GC时间戳
        • -XX:+PrintGCCause:GC原因
        • 一共五个日志文件,每个20M,共100M。
      2. 或者每天产生一个日志文件(不可以的,每天的日志量太大,不好差)
    7. 观察日志情况

c、案例1

  • 问:垂直电商,最高每日百万订单,处理订单系统需要什么样的服务器配置?
  1. 这个问题不太专业,因为垂直电商不可能做到每日百万订单。
  2. 遇到这种问法时,还是需要去分析。比如考虑高峰访问量,假设一小时产生36w订单,即100订单/秒,高峰就再次假设1000订单/秒。
  3. 接下来较考虑一个订单产生多少内存。即new出来订单对象,需要多少内存。假设一个订单对象为512k,1000订单总和是500M左右。
  4. 这样新生代设置500M就可以,当然250M也可以,多回收几次就行。所以此时一般有响应时间要求,即在多少响应时间(比如100ms)内进行设计,然后进行压测。
  5. 初次设定参数后,就可以进行压测,满足不了要求就扩大参数,再不行就加服务器数量。

d、案例2:

  • 问:12306遭遇春节大规模抢票应该如何支撑?
  1. 12306应该是中国并发量最大的秒杀网站:号称并发量100W最高

    CDN -> LVS -> NGINX -> 业务系统 -> 每台机器1W并发(10K问题) 100台机器
    一般先从CDN开始,在全国做不同的CDN缓存,接下来是一堆的LVS,接下来就是NGINX,接下来就是Tomcat等服务器。

  2. Redis可以撑得住单机1w并发。

  3. 普通电商订单 -> 下单 ->订单系统(IO)减库存 ->等待用户付款

  4. 此外,架构设计也是和业务逻辑紧密相关的。

    • 在商城付款流程中,普通电商订单 -> 下单 ->订单系统(IO)减库存,减库存和订单的生成应该是异步进行的,最后一步是用户付款。
    • 在具体的功能模块,比如订单生成,最后还会把压力压到一台服务器,可以做分布式本地库存 + 单独服务器做库存均衡。
  5. 大流量的处理方法:分而治之。

  • 怎么得到一个事务会消耗多少内存?
    1. 弄台机器,看能承受多少TPS?是不是达到目标?扩容或调优,让它达到
    2. 用压测来确定

2、调优2:优化JVM运行环境(慢、卡顿)

a、三个问题

  1. 有一个50万PV的资料类网站(从磁盘提取文档到内存)原服务器32位,1.5G的堆,用户反馈网站比较缓慢,因此公司决定升级,新的服务器为64位,16G的堆内存,结果用户反馈卡顿十分严重,反而比以前效率更低了。
    • 问题:为什么?如何优化?
  2. 系统CPU经常100%,如何调优?(面试高频)
  3. 系统内存飙高,如何查找问题?(面试高频)

b、问题1

有一个50万PV的资料类网站(从磁盘提取文档到内存)原服务器32位,1.5G的堆,用户反馈网站比较缓慢,因此公司决定升级,新的服务器为64位,16G的堆内存,结果用户反馈卡顿十分严重,反而比以前效率更低了。

  • 问题:为什么?
    • 很多用户浏览数据,很多数据load到内存,内存不足,频繁YGCSTW(stop the world)长,响应时间变慢
  • 为什么会更卡顿?
    • 内存越大,YGC频率变低(好事);因为空间变大,所以STW变长。FGC 时间越长
  • 如何优化?
    • 改变垃圾回收器:PS+PO(JDK1.8) 改成 PN + CMS 或者 G1

c、问题2

  • 系统CPU经常100%,如何调优?(面试高频、美团问过)

  • 我之前写过一篇文章,就是解决这个问题的
    Java面试题之cpu占用率100%,进行定位和解决

  • CPU100%那么一定有线程在占用系统资源,

    1. 找出哪个进程cpu高(top
    2. 该进程中的哪个线程cpu高(top -Hp
    3. 导出该线程的堆栈 (jstack)
    4. 查找哪个方法(栈帧)消耗时间 (jstack)
    5. 工作线程占比高 | 垃圾回收线程占比高

d、问题3

  • 系统内存飙高,如何查找问题?(面试高频)
    1. 导出堆内存 (jmap)
    2. 分析 (jhat jvisualvm jmat jprofiler … )
    3. (j开头的工具都是JDK自带的)

e、如何监控JVM

  1. jstat
  2. jvisualvm
  3. jprofiler
  4. arthas
  5. top

3、调优3:解决JVM运行出现的各种问题*****

无监控,不调优

a、风险评控-测试

i、代码

一个案例理解常用工具
测试代码:

package com.mashibing.jvm.gc;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 * 从数据库中读取信用数据,套用模型,并把结果进行记录和传输
 */

public class T15_FullGC_Problem01 {

    private static class CardInfo {
        BigDecimal price = new BigDecimal(0.0);
        String name = "张三";
        int age = 5;
        Date birthdate = new Date();

        public void m() {}
    }

    private static ScheduledThreadPoolExecutor executor = new ScheduledThreadPoolExecutor(50,
            new ThreadPoolExecutor.DiscardOldestPolicy());

    public static void main(String[] args) throws Exception {
        executor.setMaximumPoolSize(50);

        for (;;){
            modelFit();
            Thread.sleep(100);
        }
    }

    private static void modelFit(){
        List<CardInfo> taskList = getAllCardInfo();
        taskList.forEach(info -> {
            // do something
            executor.scheduleWithFixedDelay(() -> {
                //do sth with info
                info.m();

            }, 2, 3, TimeUnit.SECONDS);
        });
    }

    private static List<CardInfo> getAllCardInfo(){
        List<CardInfo> taskList = new ArrayList<>();

        for (int i = 0; i < 100; i++) {
            CardInfo ci = new CardInfo();
            taskList.add(ci);
        }

        return taskList;
    }
}

ii、定位线程占用CPU高的位置

  1. 在jvm路径下的终端中:java -Xms200M -Xmx200M -XX:+PrintGC com.mashibing.jvm.c5_gc.T15_FullGC_Problem01

  2. 一般是运维团队首先受到报警信息(CPU Memory)

  3. top命令观察到问题:内存不断增长 CPU占用率居高不下。找到高内存的pid进程号。
    老师讲解的:
    我的Mac:内存占了46.7%,在越来越大。
    JVM知识体系学习七:了解JVM常用命令行参数、GC日志详解、调优三大方面(JVM规划和预调优、优化JVM环境、JVM运行出现的各种问题)_第5张图片

  4. top -Hp pid(进程号):打印进程里的所有线程。观察线程,看哪个线程CPU和内存占比高。正常来说占CPU比较多的是垃圾回收的线程比较多,因为垃圾太多回收不过来了,每次只能回收一点点。

  5. jstack:查看使用方法。可以定位具体的线程,查看问题。注意:jstack 所需的 pid号 是十六进制,通过 top 得到的 进程/线程号 都是十进制的,所以需要十进制转十六进制。
    JVM知识体系学习七:了解JVM常用命令行参数、GC日志详解、调优三大方面(JVM规划和预调优、优化JVM环境、JVM运行出现的各种问题)_第6张图片
    jstack pid(进程):会把该进程下的所有线程都给打印出来。
    最开始的线程,这里起了50个线程,所以这里是50开始的,倒序的。
    还有一个点,需要看**线程的状态**。 最后的线程,中间省略啦。
    Reference Handler线程:处理引用,JVM内部的线程。
    Finalizer线程:垃圾回收线程。
    在往下都是垃圾回收的线程。

  6. jps:java 的 ps,打印java 的相关进程。即定位具体java进程。(win、Linux 都行)
    jstack: 定位线程状况,重点关注:WAITING、BLOCKED
    eg.
    waiting on <0x0000000088ca3310> (a java.lang.Object) 很重要意思就是:waiting 正在等待这把锁的释放,
    jstack pid(进程):会将进程里的所有线程都给列举出来。
    假如有一个进程中100个线程,很多线程都在 waiting on ,一定要找到是哪个线程持有这把锁
    怎么找?搜索 jstack dump 的信息,找 ,看哪个线程持有这把锁RUNNABLE
    作业:1:写一个死锁程序,用jstack观察 2 :写一个程序,一个线程持有锁不释放,其他线程等待

  7. 为什么阿里规范里规定,线程的名称(尤其是线程池)都要写有意义的名称?
    答:创建线程或者线程池时请指定有意义的线程名称,方便出错时回溯。

    public class TimerTaskThread extends Thread {
        public TimerTaskThread(){
            super.setName("TimerTaskThread");
            ...
        }
    }
    

    怎么样自定义线程池里的线程名称?
    答:(自定义ThreadFactory)

  8. jinfo pid(进程号):打印进程的虚拟机详细信息。
    JVM知识体系学习七:了解JVM常用命令行参数、GC日志详解、调优三大方面(JVM规划和预调优、优化JVM环境、JVM运行出现的各种问题)_第7张图片

    等等。

  9. jstat -gc:(不好用,可视化不好用)动态观察gc情况 / 阅读GC日志发现频繁GC / arthas观察 / jconsole/jvisualVM/ Jprofiler(最好用,但是花钱)(下面一一讲解了)
    jstat -gc 4655 500 : 每个500个毫秒打印GC的情况。
    JVM知识体系学习七:了解JVM常用命令行参数、GC日志详解、调优三大方面(JVM规划和预调优、优化JVM环境、JVM运行出现的各种问题)_第8张图片

    如果面试官问你是怎么定位OOM问题的?如果你回答用图形界面(错误)

    • 已经上线的系统不用图形界面,用什么?(用 cmdline(在远程服务器就可以看)、 arthas(阿里的)
      因为 上线的项目绝不会使用JMX等线程时时刻刻的监控,太影响项目了。
    • 图形界面到底用在什么地方?测试!测试的时候进行监控!(压测观察)
  10. jmap - histo 4655 | head -20,查找有多少对象产生

  11. jmap -dump:format=b,file=xxx pid :jmap命令:https://www.jianshu.com/p/a4ad53179df3
    线上系统,内存特别大,jmap执行期间会对进程产生很大影响,甚至卡顿(电商不适合)
    1:设定了参数HeapDump,OOM的时候会自动产生堆转储文件
    2:很多服务器备份(高可用),停掉这台服务器对其他服务器不影响
    3:在线定位(一般小点儿公司用不到)

    这个命令执行,JVM会将整个heap的信息dump写入到一个文件,heap如果比较大的话,就会导致这个过程比较耗时,并且执行的过程中为了保证dump的信息是可靠的,所以会暂停应用, 线上系统慎用。

  12. java -Xms20M -Xmx20M -XX:+UseParallelGC -XX:+HeapDumpOnOutOfMemoryError com.mashibing.jvm.gc.T15_FullGC_Problem01

  13. 使用MAT / jhat /jvisualvm 进行dump文件分析
    https://www.cnblogs.com/baihuitestsoftware/articles/6406271.html
    jhat -J-mx512M xxx.dump

http://192.168.17.11:7000
拉到最后:找到对应链接
可以使用OQL查找特定问题对象

  1. 找到代码的问题

iii、作业:1:写一个死锁程序,用jstack观察 2 :写一个程序,一个线程持有锁不释放,其他线程等待

b、jconsole远程连接(图形监控)

Linux没有图形化界面,一般都是win链接Linux;一般远程很少使用图像化界面观察得到, 一般可以使用在线跟踪,阿里的arthas,当然远程监控也有用。

jconsole远程连接时,远程需要开一些服务,JMX(Java Manager Extensions,java管理拓展),就是远程管理、监控一些java进程,需要在服务器上的JMX打开。然后用支持的JMX的工具去连接展示即可
JVM知识体系学习七:了解JVM常用命令行参数、GC日志详解、调优三大方面(JVM规划和预调优、优化JVM环境、JVM运行出现的各种问题)_第9张图片

  1. 程序启动加入参数(开启JMX):

    java -Djava.rmi.server.hostname=192.168.17.11 -Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.port=11111 -Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.ssl=false 接下来的参数。。。

    全的参数:

    java -Djava.rmi.server.hostname=192.168.17.11 -Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.port=11111 -Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.ssl=false java -Xms200M -Xmx200M -XX:+PrintGC com.mashibing.jvm.c5_gc.T15_FullGC_Problem01

  2. 如果遭遇 Local host name unknown:XXX的错误,修改/etc/hosts文件,把XXX加入进去

    192.168.17.11 basic localhost localhost.localdomain localhost4 localhost4.localdomain4
    ::1 localhost localhost.localdomain localhost6 localhost6.localdomain6

  3. 关闭linux防火墙(实战中应该打开对应端口)

    service iptables stop
    chkconfig iptables off #永久关闭

  4. windows上打开 jconsole远程连接 192.168.17.11:11111

c、jvisualvm远程连接(了解即可)

有限制,不如JMX协议。
https://www.cnblogs.com/liugh/p/7620336.html (简单做法)
JVM知识体系学习七:了解JVM常用命令行参数、GC日志详解、调优三大方面(JVM规划和预调优、优化JVM环境、JVM运行出现的各种问题)_第10张图片

  • mac的路径:/Library/Java/JavaVirtualMachines/jdk1.8.0_202.jdk/Contents/Home/bin

  • 我这里以本地具体。页面展示如下:

  1. 概述:参数等信息
  2. 监视:CPU、堆、元空间、类、线程等信息。
  3. 线程
  4. 抽样器:可以看到类的加载大小情况等,右边有字节和实例个数,可以从这里看出来是哪个类导致的OOM。
  5. jprofile

d、jprofiler (收费)

e、阿里的arthas在线排查工具

  • 为什么需要在线排查?
    在生产上我们经常会碰到一些不好排查的问题,例如线程安全问题,用最简单的threaddump或者heapdump不好查到问题原因。为了排查这些问题,有时我们会临时加一些日志,比如在一些关键的函数里打印出入参,然后重新打包发布,如果打了日志还是没找到问题,继续加日志,重新打包发布。对于上线流程复杂而且审核比较严的公司,从改代码到上线需要层层的流转,会大大影响问题排查的进度。
  • jvm观察jvm信息
  • thread定位线程问题
  • dashboard 观察系统情况
  • heapdump + jhat分析
  • jad反编译
    动态代理生成类的问题定位
    第三方的类(观察代码)
    版本问题(确定自己最新提交的版本是不是被使用)
  • redefine 热替换
    目前有些限制条件:只能改方法实现(方法已经运行完成),不能改方法名, 不能改属性
    m() -> mm()
  • sc - search class
  • watch - watch method
  • 没有包含的功能:jmap

你可能感兴趣的:(JVM,jvm,学习,java)