天天看点

jvm优化及使用工具

常见线上问题

  • 内存泄漏
  • 某个进程cpu突然飙升
  • 线程死锁
  • 响应变慢

处理方式

  • 在本地可以使用本地调试工具。
  • 线上:基于数据收集来定位,而数据收集离不开监控工具的处理,比如:运行日志,异常堆栈、GC日志、线程快照、堆快照。

JVM常见监控工具 和 指令

  1. jps:jvm进程状况工具
jps [options] [hostid]
           

如果不指定hostid 就默认为当前主机或服务器;

命令行参数选项说明:

-q  不输出类名、Jar名和传入mian方法的的参数
-l  输出main类或Jar的权限名
-m  输出传入main方法的参数
-v  输出传入JVM的参数
           

例如:

jvm优化及使用工具
  1. jstst:jvm统计信息监控工具

jstat是用于显示虚拟机各种运行状态信息的命令行工具。它可以显示本地或者远程虚拟机进程中的类装载、内存、垃圾收集、jit编译等运行数据、它是线上定位jvm性能的首选工具。

命令行参数选项说明:

jstat [ generalOption | outputOptions vmid [interal[s|ms]]
generalOption -单个常用的命令行选项、 如 -help , -options,或 -version。
outputOptions - 一个或多个输出选项,由单个的statOption选项组成、可以和-t、-h、,and -J等选项配合使用。

           
Option DIsplays Ex
class 用于查看类加载情况的统计 jstat -class pid:显示加载calss的数量,及所占空间等信息
compiler 查看HotSpot中即使编译器的编译情况的统计 jstat -compoiler pid:显示VM实时编译的数量等信息。
gc 查看JVM中堆的垃圾收集情况的统计 jstat -gc pid:可以显示GC的信息,查看gc的次数,及时间。其中最后五项,分别是young gc的次数,young gc 的时间,full gc 的次数, full gc 的时间, gc 的总时间。
gccapacity 查看新生代、老生代及持久代的存储容量情况 jstat -gccapacity:可以显示,VM内存中三代(young,old,perm)对象的使用和占用大小
gccause 查看垃圾收集的统计情况(这个和-gcutil选项一样),如果有发生垃圾收集,它还会显示最后一次及当前正在发生垃圾收集的原因。 jstat -gccause:显示gc原因
gcnew 产看新生代垃圾收集的情况 jstat -gcnew pid:new 对象的信息
gcnewcapacity 用于查看新生代的存储情况 jstat -gcnewcapacity pid:new 对象的信息及其占用量
gcold 用于查看新生代的存储容量情况 jstat -gcold oid:old对象的信息
gcoldcapacity 用于查看老生代的容量 jstat -gcoldcapacity pid:old对象的信息及其占用量
gcpermcapacity 用于查看持久代的容量 jstat -gcpermcapacity pid: perm对象的信息及其占用量
gcutil 查看新生代、老生代及持代垃圾收集的情况 jstat -util pid:统计gc信息统计
printcompilation HotSpot编译方法的统计 jstat -printcompilation pid:当前VM执行的信息

例如:

jvm优化及使用工具
  1. jinfo: java配置信息

    命令格式:

jinfo[option] pid
           

比如:获取一些当前的进程jvm运行和启动信息。

jvm优化及使用工具
  1. jmap: java内存映射工具

    jmap命令用于生产堆转存快照。打印出某个java 进程内存内的,所由对象的情况(如:产生那些对象,及其数量)。

    命令格式:

jmap [ option ] pid

jmap [ option ] executable core

jmap [ option ] [server-id@]remote-hostname-or-IP
           

参数选项:

-dump:[live,]format=b,file=<filename> 使用hprof二进制形式,输出jvm的heap内容到文件=. live子选项是可选的,假如指定live选项,那么只输出活的对象到文件. 

-finalizerinfo 打印正等候回收的对象的信息.

-heap 打印heap的概要信息,GC使用的算法,heap的配置及wise heap的使用情况.

-histo[:live] 打印每个class的实例数目,内存占用,类全名信息. VM的内部类名字开头会加上前缀”*”. 如果live子参数加上后,只统计活的对象数量. 

-permstat 打印classload和jvm heap长久层的信息. 包含每个classloader的名字,活泼性,地址,父classloader和加载的class数量. 另外,内部String的数量和占用内存数也会打印出来. 

-F 强迫.在pid没有相应的时候使用-dump或者-histo参数. 在这个模式下,live子参数无效. 

-h | -help 打印辅助信息 

-J 传递参数给jmap启动的jvm. 

           

例如:

使用jmap -heap pid查看进程堆内存使用情况,包括使用的GC算法、堆配置参数和各代中堆内存使用情况:

jvm优化及使用工具
  1. jhat:jvm堆快照分析工具

    jhat 命令与jamp搭配使用,用来分析map生产的堆快存储快照。jhat内置了一个微型http/Html服务器,可以在浏览器找那个查看。不过建议尽量不用,既然有dumpt文件,可以从生产环境拉取下来,然后通过本地可视化工具来分析,这样既减轻了线上服务器压力,有可以分析的足够详尽(比如 MAT/jprofile/visualVm)等。

  2. jstack:java堆栈跟踪工具

    jstack用于生成java虚拟机当前时刻的线程快照。线程快照是当前java虚拟机内每一条线程正在执行的方法堆栈的集合,生成线程快照的主要目的是定位线程出现长时间停顿的原因,如线程间死锁、死循环、请求外部资源导致的长时间等待等。

命令格式:

jstack [ option ] pid

jstack [ option ] executable core

jstack [ option ] [server-id@]remote-hostname-or-IP
           

参数:

jstack [ option ] pid

jstack [ option ] executable core

jstack [ option ] [server-id@]remote-hostname-or-IP
           

查询消耗最高cpu是使用。

应用

1. cpu飙升

在线上某个时刻,可能会出现某个应用 cpu 飙升的问题,对此我梦应该熟悉一些指令,快速查对应的代码。

  1. 找到最耗cpu的进程
指令 top
           
jvm优化及使用工具
  1. 找到该进程下最消耗cpu的线程
指令:top -HP pid
           
jvm优化及使用工具
  1. 转换进制

    printf "%x\n" 2706 // 转换16进制(转换后为 a92)

  2. ** 过滤指定线程,打印堆栈信息**

    指令:

jstack pid |grep 'threadPid'  -C5 --color 

jstack 13525 |grep '0x3be4'  -C5 --color  //  打印进程堆栈 并通过线程id,过滤得到线程堆栈信息。
           

例如

jstack 2706 |grep ‘a92’ -C5 --color

jvm优化及使用工具

可以看到一个上报程序,占用 过多cpu 了, (以上知识例子,其实本身cpu

并不高)

2. 线程死锁

有时候部署场景会有线程死锁的问题发生,但是不常见,此时我们采用jstack查看一些,比如说此时已经有一个线程死锁的程序,导致某些操作waiting中。

  1. 查找java进程id
指令:top 或者 jps

           
jvm优化及使用工具
  1. 查看java进程的线程快照信息
指令: jstack -l pid
           
jvm优化及使用工具

从输出信息可以看到, 有一个线程死锁发生,并且指出了那行代码出现的。 如此可以快速排序查问题

3. OOM 内存泄露

java堆内 的 OOM异常是实际应用中常见的内存溢出异常。一般我们都是先通过内存映射分析工具(比如MAT)对dump 出来的堆转存快照进行分析,确认内存中对象是否出现问题。

当然了出现 OOM 的原因由很多,并非是堆中申请资源不足的一种情况。还由可能是申请太多资源定没由释放,或者频繁申请,系统资源耗尽。针对这三种情况我需要 一一 排查。

OOM的三种情况 :

1.申请资源(内存)过小,不够用。

2.申请资源太多,没有释放。

3.申请资源过多,资源耗尽。比如:线程过多,线程内存过大等。
           
  1. 排查申请资源问题。

    指令: jmap -heap 6380

    查看新生代,老年代堆内存的分配大小以及使用情况,看是否本身分配过小。
    jvm优化及使用工具

发现程序申请的内存没有问题

  1. 排查gc

    特别是fgc情况下,各个分代内存情况

指定: jstat -gcutil 6380 1000 每一秒输出一次gc的分代内存分配情况,以及gc时间
           
jvm优化及使用工具
  1. 查找最废内存定的对象
指令: jmap -histo:live 6380 | more
           
jvm优化及使用工具

上述输出信息中,最大内存对象10mb,属于正常范围。如果某个对象占用空间很大,比如超过了 100Mb ,因该着重分析,为何没有释放。

命令参数:

jmap -histo:live 11869 | more

执行之后,会造成jvm强制执行一次fgc,在线上不推荐使用,可以采取dump内存快照,线下采用可视化工具进行分析,更加详尽。

jmap -dump:format=b,file=/tmp/dump.dat 11869 

或者采用线上运维工具,自动化处理,方便快速定位,遗失出错时间。


           
  1. 确认资源是否耗尽
pstree 查看进程线程数量
netstat 查看网络连接数量
           

或者

ll /proc/${PID}/fd | wc -l // 打开的句柄数
ll /proc/${PID}/task | wc -l (效果等同pstree -p | wc -l) //打开的线程数