06-JVM-监控及调优案例

一、常用JVM监控指令

进程监控-jps

jps [pid] 查看java进程

jvm信息查看-jinfo

  1. jinfo -flags [pid] 查看jvm所有参数
  2. **jinfo -flag 【具体参数名称】 【pid】查看具体参数 **
  3. **jinfo -flag name=value 【pid】设置某个参数 **

信息监控-jstat

jstat -gc -t -h30 9895 1s 300

-t:显示系统运行的时间
-h30:间隔30行数据,输出一次表头
9895:Java进程ID
1s:时间间隔
300:本次输出的数据行数```

## 堆内信息统计-jmap

jmap工具实际使用方式:jmap -heap [pid]或jmap -dump:live,format=b,file=Dump.phrof [pid]等。
堆快照导出命令解析:
live:导出堆中存活对象快照;format:指定输出格式;file:指定输出的文件名及其格式(.dat、.phrof等格式)。```

堆栈跟踪工具-jstack

jstack工具主要用于捕捉JVM当前时刻的线程快照,线程快照是JVM中每条线程正在执行的方法堆栈集合。在线上情况时,生成线程快照文件可以用于定位线程出现长时间停顿的原因,如线程死锁、死循环、请求外部资源无响应等等原因导致的线程停顿。
当线程出现停顿时,可以通过jstack工具生成线程快照,从快照信息中能查看到Java程序内部每条线程的调用堆栈情况,从调用堆栈信息中就可以清晰明了的看出:发生停顿的线程目前在干什么,在等待什么资源等。

jstack -l [pid]

JVM问题排查

线上排查OOM异常

OOM异常大致分为两种,一种是内存溢出,而另一种是内存泄漏

内存溢出

内存溢出的出现的场景
1. 短时间内并发量突然增大
2. 一次读取过大的对象到内存中,比如报表、excel等大型文件
3. 一次性从外部将体积过于庞大的数据载入内存,如DB读表、读本地报表文件等。
4. 程序中使用容器(Map/List/Set等)后未及时清理,内存紧张而GC无法回收。
5. 程序逻辑中存在死循环或大量循环,或单个循环中产生大量重复的对象实例。
6. 程序中引入的第三方依赖中存在BUG问题,因此导致内存出现故障问题。
7. 程序中存在内存溢出问题,一直在蚕食可用内存,GC无法回收导致内存溢出。
8. 第三方依赖加载大量类库,元空间无法载入所有类元数据,因而诱发OOM。

问题排查
获取dump文件至本地,用mat来分析,定位问题位置

内存泄漏

出现场景

  1. 存在静态对象引用着不用的对象
  2. 各种资源连接忘记关闭

排查手段同上

线程死锁

排查手段 jps+jstack

D:\> jps
19552 Jps
2892 DeadLock
jstack -l 2892

06-JVM-监控及调优案例_第1张图片
可以从dump日志中明显看出,jstack工具从该进程中检测到了一个死锁问题,是由线程名为T1、T2的线程引起的,而死锁问题的诱发原因可能是DeadLock.java:41、DeadLock.java:25行代码引起的。而到这一步之后其实就已经确定了死锁发生的位置,我们就可以跟进代码继续去排查程序中的问题,优化代码之后就可以确保死锁不再发生。

CPU100%排查

  1. 通过top指令查看系统后台的进程状态
[root@localhost ~]# top
top - 14:09:20 up 2 days, 16 min,  3 users,  load average: 0.45, 0.15, 0.11
Tasks:  98 total,   1 running,  97 sleeping,   0 stopped,   0 zombie
%Cpu(s):100.0 us,  0.0 sy,  0.0 ni,  0.0 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
KiB Mem :   997956 total,   286560 free,   126120 used,   585276 buff/cache
KiB Swap:  2097148 total,  2096372 free,      776 used.   626532 avail Mem 

   PID USER      PR  NI    VIRT    RES    SHR S %CPU %MEM     TIME+ COMMAND
 77915 root      20   0 2249432  25708  11592 S 99.9  2.6   0:28.32 java
   636 root      20   0  298936   6188   4836 S  0.3  0.6   3:39.52 vmtoolsd
     1 root      20   0   46032   5956   3492 S  0.0  0.6   0:04.27 systemd
     2 root      20   0       0      0      0 S  0.0  0.0   0:00.07 kthreadd
     3 root      20   0       0      0      0 S  0.0  0.0   0:04.21 ksoftirqd/0
     5 root       0 -20       0      0      0 S  0.0  0.0   0:00.00 kworker/0:0H
     7 root      rt   0       0      0      0 S  0.0  0.0   0:00.00 migration/0
     8 root      20   0       0      0      0 S  0.0  0.0   0:00.00 rcu_bh
     9 root      20   0       0      0      0 S  0.0  0.0   0:11.97 rcu_sched
     .......
  1. 通过top -Hp [PID]命令查看该Java进程中,CPU占用率最高的线程:
[root@localhost ~]# top -Hp 77915
.....省略系统资源相关的信息......
   PID USER      PR  NI    VIRT    RES    SHR S %CPU %MEM     TIME+ COMMAND
 77935 root      20   0 2249432  26496  11560 R 99.9  2.7   3:43.95 java
 77915 root      20   0 2249432  26496  11560 S  0.0  2.7   0:00.00 java
 77916 root      20   0 2249432  26496  11560 S  0.0  2.7   0:00.08 java
 77917 root      20   0 2249432  26496  11560 S  0.0  2.7   0:00.00 java
 77918 root      20   0 2249432  26496  11560 S  0.0  2.7   0:00.00 java
 77919 root      20   0 2249432  26496  11560 S  0.0  2.7   0:00.00 java
 77920 root      20   0 2249432  26496  11560 S  0.0  2.7   0:00.00 java
 77921 root      20   0 2249432  26496  11560 S  0.0  2.7   0:00.01 java
 .......
  1. 将线程id转化为16进制,77935–>1306f
  2. 执行 jstack 77915 | grep 1306f
[root@localhost ~]# jstack 77915 > java_log/thread_stack.log
[root@localhost ~]# vi java_log/thread_stack.log
-------------然后再按/,输入线程ID:1306f-------------
"ActiveThread-Hot" #18 prio=5 os_prio=0 tid=0x00007f7444107800
            nid=0x1306f runnable [0x00007f7432ade000]
   java.lang.Thread.State: RUNNABLE
        at CpuOverload.lambda$main$1(CpuOverload.java:18)
        at CpuOverload$$Lambda$2/531885035.run(Unknown Source)
        at java.lang.Thread.run(Thread.java:745)

三、JVM调优

内存调优

当项目执行后,多次手动执行Full GC,查看每次Full GC中老年代剩余对象大小,将堆大小设置为其的3-4倍

逃逸分析-栈上分配

JIT会对我们当前方法的局部变量进行分析,若它作用域不超过该方法,则对其进行栈上分配的优化,这样它就不会加载到堆中,有利于减少gc次数

注意:栈上分配并不是在栈上分配对象,而是对该对象的属性进行标量替换

你可能感兴趣的:(jvm,jvm,java,linux)