Loading

JVM调优

1.了解JVM常用命令行参数

HotSpot参数分类

标准: - 开头,所有的HotSpot都支持

非标准:-X 开头,特定版本HotSpot支持特定命令

不稳定:-XX 开头,下个版本可能取消

java -XX:+PrintFlagsFinal | grep xxx 找到对应的参数

java -XX:+PrintFlagsFinal -version |grep GC

参考链接:https://docs.oracle.com/javase/8/docs/technotes/tools/unix/java.html

2.调优前的基础概念

1.吞吐量:用户代码时间 /(用户代码执行时间 + 垃圾回收时间)。吞吐量优先的一般:(PS + PO)

2.响应时间:STW越短,响应时间越好。响应时间优先用G1

3.什么是调优

1.根据需求进行JVM规划和预调优

2.优化JVM运行环境(慢,卡顿)

3.解决JVM运行过程中出现的各种问题(OOM)

4.调优从规划开始

  • 调优,从业务场景开始,没有业务场景的调优都是耍流氓

  • 无监控(压力测试,能看到结果),不调优

  • 步骤

    1.熟悉业务场景(没有最好的垃圾回收器,只有最合适的垃圾回收器)

    1.响应时间、停顿时间 [CMS G1 ZGC] (需要给用户作响应)

    2.吞吐量 = 用户时间 /( 用户时间 + GC时间) [PS]

    2.选择回收器组合

    3.计算内存需求(经验值)

    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 (gc日志文件路径,循环打印,一共5个日志文件,每个文件大小20mb,打印gc详细信息,发生gc的时间和原因)

    2.或者每天产生一个日志文件

    7.观察日志情况

  • 案例1:垂直电商,最高每日百万订单,处理订单系统需要什么样的服务器配置?

    很业余的问法

    这种情况一般要估算业务最高峰值(比如5000订单/秒),根据最高峰值来估算系统资源,然后压测

  • 案例2:12306遭遇春节大规模抢票应该如何支撑?

    12306应该是中国并发量最大的秒杀网站,号称并发量100W最高

    CDN -> LVS -> NGINX -> 业务系统 -> 每台机器1W并发(10K问题) 100台机器

    大流量的处理方法:分而治之

5.优化环境

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

    1.为什么原网站慢:很多用户浏览数据,很多数据load到内存,内存不足,频繁GC,STW长,响应时间变慢

    2.升级服务器后为什么会更卡顿:内存越大,FGC时间越长

    3.如何优化:PS+PO -> PN + CMS 或者 G1,最直接的应该是从业务上优化,不要把文档加载到内存,而是用一个文件服务器之类的

  2. 系统CPU经常100%,如何调优?(面试高频)

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

    2.找出哪个进程cpu高(top)

    3.该进程中的哪个线程cpu高(top -Hp)

    4.导出该线程的堆栈 (jstack)

    5.查找哪个方法(栈帧)消耗时间 (jstack)

    6.观察是工作线程占比高 | 垃圾回收线程占比高

  3. 系统内存飙高,如何查找问题?(面试高频)

    1.导出堆内存 (jmap)

    2.分析 (jhat jvisualvm mat jprofiler ... )

  4. 如何监控JVM

    jstat jvisualvm jprofiler arthas top...

6.解决JVM运行中的问题

  • 一个案例理解常用工具

    1.测试代码:

    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;
        }
    }
    

    2.java -Xms200M -Xmx200M -XX:+PrintGC T15_FullGC_Problem01

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

    4.top命令观察到问题:内存不断增长 CPU占用率居高不下

    5.top -Hp 观察进程中的线程,哪个线程CPU和内存占比高

    6.jps定位具体java进程;jstack 定位线程状况,重点关注:WAITING BLOCKED

    eg.waiting on <0x0000000088ca3310> (a java.lang.Object)
    假如有一个进程中100个线程,很多线程都在waiting on ,一定要找到是哪个线程持有这把锁.怎么找?搜索jstack dump的信息,找 ,看哪个线程持有这把锁RUNNABLE

    7.为什么阿里规范里规定,线程的名称(尤其是线程池)都要写有意义的名称

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

    8.jinfo pid

    9.jstat -gc 动态观察gc情况 / 阅读GC日志发现频繁GC / arthas观察 / jconsole/jvisualVM/ Jprofiler(最好用)

    jstat -gc 4655 500 : 每个500个毫秒打印GC的情况

    如果面试官问你是怎么定位OOM问题的?如果你回答用图形界面(错误)
    1:已经上线的系统不用图形界面用什么?(cmdline arthas)
    2:图形界面到底用在什么地方?测试!测试的时候进行监控!(压测观察)

    10.jmap - histo 4655 | head -20,查找有多少对象产生

    11.jmap -dump:format=b,file=xxx pid :

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

    12.java -Xms20M -Xmx20M -XX:+UseParallelGC -XX:+HeapDumpOnOutOfMemoryError 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查找特定问题对象

    14.找到代码的问题

  • jconsole远程连接

    1.程序启动加入参数:

    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 XXX
    

    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

  • jvisualvm远程连接

    https://www.cnblogs.com/liugh/p/7620336.html (简单做法)

  • jprofiler (收费)

  • arthas在线排查工具

    为什么需要在线排查:在生产上我们经常会碰到一些不好排查的问题,例如线程安全问题,用最简单的threaddump或者heapdump不好查到问题原因。为了排查这些问题,有时我们会临时加一些日志,比如在一些关键的函数里打印出入参,然后重新打包发布,如果打了日志还是没找到问题,继续加日志,重新打包发布。对于上线流程复杂而且审核比较严的公司,从改代码到上线需要层层的流转,会大大影响问题排查的进度。

    jvm观察jvm信息

    thread定位线程问题

    dashboard 观察系统情况

    heapdump + jhat分析

    jad反编译

    动态代理生成类的问题定位
    第三方的类(观察代码)
    版本问题(确定自己最新提交的版本是不是被使用)

    redefine 热替换

    目前有些限制条件:只能改方法实现(方法已经运行完成),不能改方法名, 不能改属性

    sc - search class

    watch - watch method

    没有包含的功能:jmap

posted @ 2022-01-17 16:27  ZT丶  阅读(856)  评论(0编辑  收藏  举报