JVM优化

为什么要对JVM进行优化

JVM优化发生的场景(处理生产环境中发生的问题)
1.当应用布置到生产环境中,时常会出现应用卡退,无日志打印,应用程序没有反应。
2.服务器cpu负载增高。
3.多线程应用下的线程分配问题。

一、JVM运行参数

  通过设置JVM参数设置,能让JVM在各种情况下都能高效运行。

参数类型标准

标准类型参数:此类型参数在将来发布的版本中不会发生改变
    -help
    -clinet(设置JVM运行模式,初始空间小,启动快,串行垃圾回收期。适用于32位操作系统_默认,不会在64位操作中出现) java -clinet -showversion  target
    -server(设置JVM运行模式,此模式下的初始空间较大,特点启动慢运行快。并行垃圾回收器,64位操作系统)  
    -version
    -showversion 输出产品版本并继续执行功能呢
    -D<名称>=<值> 设置系统参数  实例:java -Dstring=values

-X类型参数(非标准参数)
    -Xint(在解释模式下执行文件,interpreted mode 此模式下会强制JVM执行所有字节码,一般不建议使用,因为会导致运行速度降低。) java -showversion -Xint target.class
    -Xcomp(在编译模式下执行,此模式下先编译再执行,JIT编译器对是否编译做判断,一般来说二次执行会快很多,执行时会出现明显卡顿现象,对于只执行一次编译代码就不必要编译到本地。) java -showversion -Xcomp target.class
    -Xmixed(混合模式下执行,将上面两种解释模式混合使用,JVM的默认模式,是推荐是使用的模式)

-XX类型参数(适用与JVM调优和debug操作)
    -XX:newSize 
    -XX:UserSerialGC
    -XX使用的两种方式 
        boolean类型
            -XX:[+-]<name> +-表示启用或者禁用操作
        非boolean类型
            -XX:<name>=<value>

-Xms与-Xmx参数

-Xms设置初始堆内存大小 -XX:initialHeapSize
-Xmx设置最大堆内存大小 -XX:MaxHeapSize
这两个命令是-XX类型的

查看jvm的运行参数

1.运行java命令时打印出运行参数
    Java -XX:+PrintFlagsFinal target.class
    查看之后怎么修改呢 
        java -XX:+PrintFlagFinal -XX:+ZeroTLAB target.class
        修改完成之后会有 :=true/false展示
        bool ZeroTLAB :=true {product}
2.查看正在运行的java进程的参数(jinfo)
    启动tomcat 
    (tar -xvf apache-tomcat-version.tar.gz  ./startup.sh)
    jinfo -flags <进程id> (输入完成之后就会出现一大串的进程情况)
    jps 查看正在运行的tomcat进程
    jsp -l 查看正在运行的tomcat进程 全目录
    jinfo -flag MaxHeapSize 进程id 查看单个的参数情况

二、JVM内存模型

jdk1.7内存模型

图片说明

young

年轻代young 划分为三个区域 Eden区和两个严格相等的Suvivor区,Suvivor区间中,某一时刻只会有一个被使用,另一个留作垃圾收集时复制对象用。当Eden区放满之后,GC就会将存活的对象移动到空闲的Survivor中去,根据JVM策略,经过几次垃圾回收集,仍然存活与Survivor的对象将会被转移到Tenure区中。

Tenure

Tenure老年区主要保存生命周期长的对象,一般是一些老的对象,当一些对象在young区复制转移一定的次数就会到此区域来,一般如果系统用了application级别的缓存,缓存中的对象一般会转移到此区间中。

Perm

Perm代主要保存class method filed 对象。这一部分空间一般不会溢出,除非一次性加载很多类。但在执行热部署应用服务器的时候,有时候会遇到java.outofMemoryError:PermGen spance 错误。造成的原因可能是每次热部署的时候,class类没有处理掉,这样就造成了大量的class对象保存在Perm中,解决方法是重启服务器。

virtual区

最大内存和初始内存的差值就是virtual

jdk1.8内存模型

图片说明
![图片说明]
(https://uploadfiles.nowcoder.com/images/20210408/358387792_1617897231511/1FBEE62EAB6FD38AAE0EA11D8FBEA6E0 "图片标题")

为什么要移除永久区

移除永久代是为了融合hotspot JVM与JRockit VM而做的努力,因为JRockit没有永久代,所以不需要配置永久代
,现实使用中,由于永久代内存经常不够用而发生内存泄露,爆出异常Java.lang.OutOfMemorryError.PermGen
基于此将永久区永远废除,而改用元空间,改善的目的是为了使用本地内存。

jstat命令使用 查看堆内存的使用情况

jstat [-命令选项] [vmid] [间隔时间/毫秒] [查询次数]

查看class类加载统计

jstat -class 端口IP
Loaded Bytes Unloaded Bytes times

查看编译统计

jstat -compiler 端口IP
Compiled Failed Invalid Time FailMethod

查看垃圾回收统计

jstat -gc 端口IP
jstat -gc 端口IP 2000 20 每隔两秒打印一次总共打印20此

jmap使用以及内存溢出分析

jmap -heap 端口ip

查看内存的数量以及大小

查看所有的内存对象 包括活跃的与不活跃的
jmap -histo <pid> grep | more
查看所有的内存对象 活跃的
jmap -histo <pid>:live grep | more</pid></pid>

将内存中的使用情况dump到文件中

jmap -dump:format=b,file=dumpFileName <pid>
jmap -dump:format=b,file=/tmp/dum.dat 1111</pid>

使用jhat对dump文件进行分析

jhat -port <port> <file>
jhat -port 1111 /tmp/dum.dat</file></port>

jstack使用

使用场景:某一时间段的cpu负载突然增高了,出现了死锁,死循环等
jstack