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%\bin

     编写脚本:在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

posted on 2019-01-23 10:51  追梦_坚持  阅读(819)  评论(0编辑  收藏  举报

导航