• jvm调优


    基于JDK命令行工具的监控

      JVM的参数类型:

          标准参数:-help、-server 、-client、 -version、-showversion、-cp、classpath

          X参数(非标准参数):-Xint:解释执行

                      -Xcomp:第一次使用就编译本地代码

                      -Xminxed:混合模式,JVM自己来决定是否编译成本地代码

          xx参数(非标准参数):Boolean类型:格式:-XX:[+-] <name>表示启用或禁用name参数

                            例:-XX:+UseConcMatkSweepGC

                              -XX:+UseG1GC

                      非Bollean类型:格式:-XX:<name>=<value>表示name的属性值是value

      运行时JVM参数查看

          -XX:+PrintFlagsInitial  =表示默认值   :=表示JVM修改过的值

          -XX:

          jps  查看java进程

          jinfo  查看运行实参数  

      jstat查看虚拟机统计信息

          类加载信息 -class

          垃圾回收信息 -gc

              s0c、s1c、s0u、s1u:s0和s1的总量与使用量

              ec、eu:Eden区总量与使用量

              oc、ou:old区总量与使用量

              mc、mu:Metaspace区总量和使用量

              ccsc‘ccsu:压缩类空间总量与使用量

              ygc、ygct:youngGC的次数与时间

              FGC、FGCT:FullGC的次数和时间

              GCT:总的GC时间

              JVM的内存结构:

                    

          JIT编译信息 -compiler

      jmap+MAT实战内存溢出

          内存溢出自动导出映像文件: -XX:HeapDumpOnOutOfMemoryError

                        -XX:HeapDumpPath=./

          使用jmap命令手动导出:jmap - help 帮助

                     jmap -dump:format=b,file=heap.hrof

          MAT分析:将导出的.hrof文件打开分析各个对象的哥数量和占用的内存

      jstack实战系循环与死锁

          命令 jstack pid > 文件名

          java线程的状态:

            NEW:新new一个线程,还没有启动

            RUNNABLE:运行状态,并不是就一定执行,可能会等待CPU资源,当获得资源才真正执行

            BLOCKED:等待一个锁

            WAITING:等待令一个线程来操作

            TIMED_WAITING:等待另一个线程来操作

            TETMINATED:线程结束 

          状态转化过程

             

          

     基于JVisualVM的可视化监控

        监控本地Tomcat

        监控远程tomcat

        监控普通的JAVA进程

    基于Btrace的监控调试

        Btrace可以动态地向目标应用程序的字节码注入追踪代码

         下载Btrace,新建环境变量BTRACE_HOME,添加Path   %BTRACE_HOME%in

         编写脚本:在idea中编写,需要引入jar包 btrace-agent.jar、btrace-boot.jar、btrace-client.jar

            

     1 import com.sun.btrace.annotations.*;
     2 import static com.sun.btrace.BTraceUtils.*;
     3 import com.sun.btrace.AnyType;
     4 import com.sun.btrace.BTraceUtils;
     5 
     6 @BTrace
     7 public class TracingScript {
     8     @OnMethod(
     9             clazz="com.fg.jvmstudy.chapter.MemoryController",
    10             method="heap",
    11             location=@Location(Kind.ENTRY)
    12     )
    13     public static void anyRead(@ProbeClassName String pcn, @ProbeMethodName String pmn, AnyType[] args) {
    14         BTraceUtils.printArray(args);
    15         BTraceUtils.println(pcn+","+pmn);
    16         BTraceUtils.println();
    17     }
    18 }

          命令行执行脚本:btrace <PID> <trace_script>

                  在jvisualvm中运行

        使用详解

          拦截方法

            

           拦截的时机:

            在入口的地方拦截:默认就是在入口的时候拦截

            在返回时拦截:在AnyType前加@return

             拦截异常

             拦截某一行代码:在Location加入line参数指定需要拦截的行号

         拦截this,入参,返回

            this:@Self

            入参:可以用AnyType,也可以用真实类型,同名的参数用真实类型

            返回值:@Return

            简单类型:直接获取

            复杂类型:反射,类名+属性名,需要指定复杂类型的classpath

         注意事项:

            默认只能本地运行

            生产环境下可以使用,但是被修改的字节码不会被还原

    tomcat性能监控与调优

         tomcat远程debug

            jdwp:定义了调试器和被调试的Java虚拟机之间的通信协议

            配置远程tomcat

                修改startup.sh

                    

                修改catalina.sh

                    

           idea:连接远程debug服务并启动

         tomcat-managet监控

            文档:docs/manager-howto.html

            步骤:

               conf/tomcat-users.xml添加用户

                 cof/Catalina/localhost/manager.xml配置允许的远程连接

                 重启

         psi-probe监控

            连接步骤与tomcat-manage监控一样

            内容:

              application:应用的统计信息、请求、session、jsp预编译

              data sources

              Deployment          

              Logs

              Threads

              Clister

              System

              Connectors

              Certificates

              Quick check

           tomcat调优

            内存

            线程

              maxConnections:最大连接数

              acceptCount:线程队列

              maxThreads:工作线程数

              minSpareThreads:最小空闲的工作线程数

            配置

              autoDeploy:是否周期性检查是否有新的应用进行部署

               enableLookups:在调用request.getRemoteHost()做dns查询,false时直接返回IP

              reloadable:是否监控WEB-INF下的class和lib,有变化时自动加载

              protocol:连接器

              session:可以禁用session

    Nginx性能监控与调优

        ngx_http_stub_status监控连接信息

            需要将此模块编译,默认已编译

            添加配置

                localhsot = /nginx_status{

                    stub_status on;  打开stub_status

                    access_log off;  关闭access_log

                    allow 127.0.0.1  允许本机

                    deny all;       拒绝所有

                }

            cat 文件  打开文件

        ngxtop监控信息

          安装python-pip

            yum install epel-release

            yum install python-pip

          安装ngxtop

            pip install ngxtop

          指定配置文件:ngxtop -c 文件路径

          查询状态是200:ngxtop -c 文件路径 -i ‘status

          查询访问最多IP:ngxtop -c 文件路径 -g remote_addr

        nginx-rrd图形化监控

        nginx优化

          配置线程数和并发连接数

            worher_processes 4; 受限于cpu

            events{

              worker_connections; 每个进程打开的最大连接数,包含了nginx与客户端和nginx与upstream之间的连接,受限与操作系统

              multi_accept on; 可以一次建立多少个连接

              use epoll;

            }

          启用长连接

            upstream server_pool{

              server lcoalhost:8080 weight=1 max_fail=2

              .......(多个服务)

              keeoalive 300;(三百个长连接)

            }

          启用缓存压缩

            

          操作系统优化

            sysctl.conf文件

     JVM层GC调优

      JVNM的内存结构

        运行时的数据区(规范):

           程序计数器 PC Register

             JVM支持多线程同时执行,每个线程都有自己的PC Register,线程正在执行的方法叫做当前方法,如果是java代码,PC Register里面存放的就是当前正在执行的指令的地址,如果是C代码,则为空

           虚拟机栈JVM Stacks

             Java虚拟机栈是线程私有的,它的生命周期与线程相同。虚拟机栈描述的是Java方法执行的内存模型:每个方法在执行的同时都回船舰一个栈帧,用于存储局部变量表、操作数栈、动态链接、方法出口等信息。每个方法从调用直至执行完成的过程,就对应着一个栈帧在虚拟机中入栈到出栈的过程。

           堆Heap

             Java堆是Java虚拟机所管理的内存中最大的一块。堆是被所有想成共享的一块内存区域,在虚拟机启动时创建。此内存区域的唯一目的就是存放对象实例,几乎所有的对象实例都在这里分配内存。

             Java堆可以处于物理上不连续的内存空间,只要逻辑上市连续的即可。

           方法区Method Area

             方法区与Java堆一样,是各个线程共享的内存区域,它用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。虽然Java虚拟机规范把方法区描述为堆的一个逻辑部分,但是它却有一个别名叫做Non-Heap,目的是与Java堆区分开来。

           常量池Run-Time Constant Pool

             运行时常量池时方法区的一部分。Class文件中除了有类的版本、字段、方法、接口等描述信息外,还有一项信息时常量池,用于存放编译期生成的各种字面量和符号引用,这部分内容将在类加载后进入方法区的运行时常量池中存放。

          本地方法栈Native Method Stack

          JVM的内存结构:

                    

          

          

      垃圾回收算法

        思想:枚举跟节点,做可达性分析

        根节点:类加载器、Thread、虚拟机栈的本地变量表static成员、常量引用、本地方法栈的变量等等

        标记清除

          算法:

            分为标记和清除两个阶段,首先标记出所有需要回收的对象,在标记完成后统一回收所有

          缺点:

            效率不高,标记和清除两个过程效率都不高,产生碎片,碎片太多会导致提前GC

        复制

          算法:

            它将可用内存按容量划分为大小相等的两块,每次只是用其中的一块,当者一块的内存用完了,就将还存活着的对象复制到另一块上面,然后再把已使用过的内存空间一次清理掉

          优缺点:

            实现简单,运行高效,空间利用率低

        标记整理

          算法

            标记过程仍然与标记清除算法一样,但后续步骤不是直接对可回收对象进行清理,而是让所有存活的对象都向一端移动,然后直接清理掉端边界以外的内存

          优缺点

            没有了内存碎片,但是整理时耗时

        分带垃圾回收

          young区用复制算法

          Old区用标记清除或者标记整理

          对象优先在Eden区分配

          大对象直接进入老年代:-XX:PretenureSizeThreshold

          长期存活对象进入老年代:

                -XX:MaxTenuringThreshold

                -XX:+PrintTenuringDistribution

                -XX:TargetSurvivorRatio

      垃圾收集器

        串行收集器Serial:Serial、Serial Old

          -XX:+UserSerialGC,-XX:UseSerialOldGC

        并行收集器Parallel:Parallel Scavenge、Parall Old,

          暂停应用程序,开启多个垃圾收集线程,结束后自动启用应用程序

          吞吐量优先

          -XX:+UseParallelGC,-XX:+UseParallelOldGC

          Server模式下的默认收集器

          自适应

            -XX:MaxGCPauseMillis=<N>   最大等待时间

            -XX:GCTimeRatio=<N>    吞吐量

            -Xmx<N>          堆大小

            注:不是最优

          动态内存调整

             -XX:YoungGenerationSizelncrement=<Y> Young区增大默认20%

             -XX:TenuredGenerationSizelncrement=<T> Old区增大默认20%

             -XX:AdaptiveSizeDecrementScaleFactor=<D> 减小默认4%

        并发收集器Concurrent:CMS、G1,停顿时间

          响应时间优先

          CMS:-XX:+UseConcMarkSweepGC,-XX:+UseParNewGC

            过程:

              1、CMS initial mark:初始标记Root,STW

              2、CMS concurrent mark:并发标记

              3、CMS-concurrent-preclean:并发预清理

              4、CMS remark:重新标记,STW

              5、CMS concurrent sweep:并发清除

              6、CMS-concurrent-reset:并发重置

            缺点:

              CPU敏感、浮动垃圾、空间碎片

            CMS的相关参数

              -XX:ConcGCThreads:并发的GC线程数

              -XX:+UseCMSCompactAtFullCollection:FullGC后做压缩

              -XX:+CMSFullGCsBeforeCompaction:多少次FullGC之后做压缩

              -XX:CMSSlnitiatingOccupancyFraction:触发FullGC

              -XX:+UseCMSInitiatingOccupancyOnly:是否动态调整

              -XX:+CMSScavengeBeforeRemark:FullGC之前先做YGC

              -XX:+CMSClassUnloadingEnabled:启用回收Perm区

            iCMS:适用于单核或双核  

          G1:-XX:+UseG1GC(jdk7以后)

            

        并行(Parallel):指多条垃圾收集线程并行工作,但此时用户线程仍然处于等待状态。适合科学计算、后台处理等弱交互场景

        并发(Concurrent):指用户线程与垃圾收集线程同时执行(但不一定是并行的,可能会交替执行),垃圾收集线程在执行的时候不会停顿用户程序的运行。适合对响应的时间有要求的场景,比如WEB

        停顿时间:垃圾收集器做垃圾回收中断应用执行的时间。

             -XX:maxGCPauseMillis

        吞吐量:花在垃圾收集的时间和花在应用时间的占比。

             -XX:GCTimeRatio=<n>,垃圾收集时间占:1/1+n

        垃圾收集器搭配

            

         如何选择垃圾收集器

           优先调整堆的大小让服务器自己选择

           如果内存小于100M,使用串行收集器

           如果是单核,并且没有停顿时间的要求,串行或者JVM自行选择

           如果允许停顿时间超过1秒,选择并行或者JVM自己选

             如果响应时间最重要,并且不能超过1秒,使用并行收集器

           

      可视化GC日志分析工具

       

    Java代码层的调优

      jvm字节码指令与javap

      i++与++i

        i++:先使用再++

        ++i:先++再使用

        字节码:

          

      字符串拼接

        String str = "";

        for(int=0;i<10;i++){

          str = str + "A";

        }

        字节码

          

       Try-funlly

        String str = "a";

        try{

          return str;

        }

        finally{

          str = "b"

        }

        

      String Constant Variable 

        

         

    常用代码优化方法

      尽量重用对象,不要循环创建对象,

      容器类初始化的时候指定长度

      ArrayList随机遍历快,LinkedList添加删除快

      集合遍历的时候尽量减少重复计算

      使用Entry遍历Map 

      大数组复制用System.arraycopy

      尽量使用基本类型而不是包装类型

      不要手动调用System.gc()

      及时消除过期对象的引用,防止内存泄漏

      尽量使用局部变量,减小变量的作用域

      尽量使用非同步的容器

      尽量减小同步代码块范围

      ThreadLocal缓存线程不安全的对象,SimpleDateFormat

      尽量使用延迟加载

      尽量减少使用反射,加缓存

      尽量使用连接池、线程池、对象池、缓存

      及时释放资源

      慎用异常,不要用抛异常来表示正常的业务逻辑

      String操作尽量少用正则表达式

      日志输出注意使用不同的级别

      日志中参数拼接使用占位符

        

    附录:

    jdk8工具集

    https://docs.oracle.com/javase/8/docs/technotes/tools/unix/index.html

    Troubleshooting

    https://docs.oracle.com/javase/8/docs/technotes/guides/troubleshoot/

    jps

    https://docs.oracle.com/javase/8/docs/technotes/tools/unix/jps.html

    jinfo

    https://docs.oracle.com/javase/8/docs/technotes/tools/unix/jinfo.html

    jstat

    https://docs.oracle.com/javase/8/docs/technotes/tools/unix/jstat.html

    jmap:

    https://docs.oracle.com/javase/8/docs/technotes/tools/unix/jmap.html

    mat:

    http://www.eclipse.org/mat/downloads.php

    jstack:

    https://docs.oracle.com/javase/8/docs/technotes/tools/unix/jstack.html

    java线程的状态

    https://docs.oracle.com/javase/8/docs/technotes/guides/troubleshoot/tooldescr034.html

    java线程状态转化:

    https://mp.weixin.qq.com/s/GsxeFM7QWuR--Kbpb7At2w

    死循环导致CPU负载高

    https://blog.csdn.net/goldenfish1919/article/details/8755378

    正则表达式导致死循环:

    https://blog.csdn.net/goldenfish1919/article/details/49123787

    jvisualVM:

    https://docs.oracle.com/javase/8/docs/technotes/guides/visualvm/index.html

    https://visualvm.github.io/documentation.html

    jvisulaVM如何添加插件

    https://visualvm.github.io/index.html

    btrace下载

    https://github.com/btraceio/btrace

    https://github.com/btraceio/btrace/releases/tag/v1.3.11

    jdwp协议:

    https://www.ibm.com/developerworks/cn/java/j-lo-jpda3/

    tomcat-manager:

    {tomcat}/webapps/docs/manager-howto.html

    psi-probe:

    https://github.com/psi-probe/psi-probe

    tomcat优化相关参数:

    ${tomcat}/webapps/docs/config/http.html

    ${tomcat}/webapps/docs/config/host.html

    ${tomcat}/webapps/docs/config/context.html

    ${tomcat}/webapps/docs/connectors.html

    apr连接器:

    http://apr.apache.org/

    nginx官网文档

    http://nginx.org/en/docs/

    nginx安装:

    http://nginx.org/en/linux_packages.html

    ngx_http_stub_status:

    http://nginx.org/en/docs/http/ngx_http_stub_status_module.html

    ngxtop:

    https://github.com/lebinh/ngxtop

    nginx-rdd

    http://www.linuxde.net/2012/04/9537.html

    jvm的运行时数据区

    https://docs.oracle.com/javase/specs/jvms/se8/html/index.html

    Metaspace

    http://ifeve.com/jvm-troubleshooting-guide-4/

    压缩类空间

    https://blog.csdn.net/jijijijwwi111/article/details/51564271

    CodeCache

    https://blog.csdn.net/yandaonan/article/details/50844806

    http://engineering.indeedblog.com/blog/2016/09/job-search-web-app-java-8-migration/

    GC调优指南:

    https://docs.oracle.com/javase/8/docs/technotes/guides/vm/gctuning/toc.html

    如何选择垃圾收集器

    https://docs.oracle.com/javase/8/docs/technotes/guides/vm/gctuning/collectors.html

    G1最佳实践

    https://docs.oracle.com/javase/8/docs/technotes/guides/vm/gctuning/g1_gc_tuning.html#recommendations

    G1 GC的一些关键技术

    https://zhuanlan.zhihu.com/p/22591838

    CMS日志格式

    https://blogs.oracle.com/poonam/understanding-cms-gc-logs

    G1日志格式

    https://blogs.oracle.com/poonam/understanding-g1-gc-logs

    GC日志分析工具

    http://gceasy.io/   

    GCViewer

    https://github.com/chewiebug/GCViewer

    ZGC:

    http://openjdk.java.net/jeps/333

    java虚拟机规范

    https://docs.oracle.com/javase/specs/jvms/se8/html/index.html

    java语言规范

    https://docs.oracle.com/javase/specs/jls/se8/html/index.html

    javap:

    https://docs.oracle.com/javase/8/docs/technotes/tools/unix/javap.html

    字段描述符

    https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.3.2

    方法描述符

    https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.3.3

    字节码指令:

    https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-6.html

    常量池:

    https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.4

    本地变量表:

    https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-2.html#jvms-2.6.1

    https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.7.13

    操作数栈:

    https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-2.html#jvms-2.6.2

    Code属性:

    https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.7.3

    LineNumberTable:

    https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.7.12

    constant variable:

    https://docs.oracle.com/javase/specs/jls/se8/html/jls-4.html#jls-4.12.4

    常量表达式

    https://docs.oracle.com/javase/specs/jls/se8/html/jls-15.html#jls-15.28

    String.intern

    https://blog.csdn.net/goldenfish1919/article/details/80410349

    String去重

    https://blog.csdn.net/goldenfish1919/article/details/20233263

  • 相关阅读:
    结构体struct和typedef后面接指针的含义
    C++中关于指针初始化和使用NULL的理解
    (虚)继承类的内存占用大小
    为什么构造函数不能为虚函数
    C++中变量自动初始化的问题
    CY7C68013A的一点总结
    Altium designer总结
    在Linux系统上限制远程登录的IP
    linux系统如何限制其他用户登录
    使用秘钥对登录Linux系统
  • 原文地址:https://www.cnblogs.com/fg-fd/p/9967015.html
Copyright © 2020-2023  润新知