七、jstack 50053 | more (必须掌握)
dbq@mac:~$ jstack 50053 | more 2021-02-27 15:32:08 Full thread dump Java HotSpot(TM) 64-Bit Server VM (25.131-b11 mixed mode): "pool-1-thread-71" #81 prio=5 os_prio=31 tid=0x00007fbd7313c800 nid=0x1a07 waiting on condition [0x00007000081fb000] java.lang.Thread.State: WAITING (parking) at sun.misc.Unsafe.park(Native Method) - parking to wait for <0x00000007b9673f58> (a java.util.concurrent.locks.ReentrantLock$NonfairSync) at java.util.concurrent.locks.LockSupport.park(LockSupport.java:175) at java.util.concurrent.locks.AbstractQueuedSynchronizer.parkAndCheckInterrupt(AbstractQueuedSynchronizer.java:836) at java.util.concurrent.locks.AbstractQueuedSynchronizer.doAcquireInterruptibly(AbstractQueuedSynchronizer.java:897) at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireInterruptibly(AbstractQueuedSynchronizer.java:1222) at java.util.concurrent.locks.ReentrantLock.lockInterruptibly(ReentrantLock.java:335) at java.util.concurrent.ScheduledThreadPoolExecutor$DelayedWorkQueue.take(ScheduledThreadPoolExecutor.java:1076) at java.util.concurrent.ScheduledThreadPoolExecutor$DelayedWorkQueue.take(ScheduledThreadPoolExecutor.java:809) at java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:1067) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1127) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) at java.lang.Thread.run(Thread.java:748) "Attach Listener" #80 daemon prio=9 os_prio=31 tid=0x00007fbd7287d000 nid=0x6c0b waiting on condition [0x0000000000000000] java.lang.Thread.State: RUNNABLE "pool-1-thread-70" #79 prio=5 os_prio=31 tid=0x00007fbd7313c000 nid=0x6007 waiting on condition [0x0000700005983000] java.lang.Thread.State: WAITING (parking) at sun.misc.Unsafe.park(Native Method) - parking to wait for <0x00000007b9673f58> (a java.util.concurrent.locks.ReentrantLock$NonfairSync) at java.util.concurrent.locks.LockSupport.park(LockSupport.java:175) at java.util.concurrent.locks.AbstractQueuedSynchronizer.parkAndCheckInterrupt(AbstractQueuedSynchronizer.java:836) at java.util.concurrent.locks.AbstractQueuedSynchronizer.doAcquireInterruptibly(AbstractQueuedSynchronizer.java:897) at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireInterruptibly(AbstractQueuedSynchronizer.java:1222) at java.util.concurrent.locks.ReentrantLock.lockInterruptibly(ReentrantLock.java:335) at java.util.concurrent.ScheduledThreadPoolExecutor$DelayedWorkQueue.take(ScheduledThreadPoolExecutor.java:1076) at java.util.concurrent.ScheduledThreadPoolExecutor$DelayedWorkQueue.take(ScheduledThreadPoolExecutor.java:809) at java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:1067) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1127) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) at java.lang.Thread.run(Thread.java:748) "pool-1-thread-69" #78 prio=5 os_prio=31 tid=0x00007fbd71868800 nid=0x5807 waiting on condition [0x0000700005577000] java.lang.Thread.State: WAITING (parking) at sun.misc.Unsafe.park(Native Method) - parking to wait for <0x00000007b9673f58> (a java.util.concurrent.locks.ReentrantLock$NonfairSync) at java.util.concurrent.locks.LockSupport.park(LockSupport.java:175) at java.util.concurrent.locks.AbstractQueuedSynchronizer.parkAndCheckInterrupt(AbstractQueuedSynchronizer.java:836) at java.util.concurrent.locks.AbstractQueuedSynchronizer.doAcquireInterruptibly(AbstractQueuedSynchronizer.java:897) at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireInterruptibly(AbstractQueuedSynchronizer.java:1222) at java.util.concurrent.locks.ReentrantLock.lockInterruptibly(ReentrantLock.java:335)
八、jmap
jmap -histo pid
显示对象的内存图
当我们的程序频繁GC时
Exception in thread "pool-1-thread-51" java.lang.OutOfMemoryError: GC overhead limit exceeded [Full GC (Ergonomics) 159584K->159581K(182272K), 0.5506696 secs] [Full GC (Ergonomics) 159584K->159581K(182272K), 0.5855513 secs] [Full GC (Ergonomics) 159584K->159581K(182272K), 0.5552056 secs] [Full GC (Ergonomics) 159584K->159581K(182272K), 0.5426389 secs]
可以通过这个命令查看哪些对象不被回收 (head:列出前20行)
可以多次运行该命令观察某对象是否持续增大,说明该对象不断在产生,不被回收
dbq@mac:~$ jmap -histo 52272 | head -20 对象数 占用内存字节数 num #instances #bytes class name ---------------------------------------------- 1: 638662 20437184 java.util.concurrent.locks.AbstractQueuedSynchronizer$Node 2: 283400 20404800 java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask 3: 283426 11337040 java.math.BigDecimal 4: 283400 9068800 com.mashibing.jvm.gc.TIS_FullGC_Problem01$CardInfo 5: 283400 6801600 java.util.Date 6: 283400 6801600 java.util.concurrent.Executors$RunnableAdapter 7: 283400 4534400 com.mashibing.jvm.gc.TIS_FullGC_Problem01$$Lambda$2/1826771953 8: 4726 3946808 [I 9: 2 2662728 [Ljava.util.concurrent.RunnableScheduledFuture; 10: 7312 1308256 [Ljava.lang.Object; 11: 1901 152072 [C 12: 747 85552 java.lang.Class 13: 1889 45336 java.lang.String 14: 42 26080 [B 15: 929 22296 java.util.ArrayList 16: 57 21432 java.lang.Thread 17: 185 13320 java.lang.reflect.Field
jmap还可以把整个对导出到文件,可以离线分析
format=b标识导出格式为二进制
jmap -dump:format=b,file=/User/dbq/Documents/20201108.hprof 52272
jvisualvm离线分析堆内存
线上一般不容许jmap或者远程连接,所以需要在java启动时加上-XX:+HeapDumpOnOutOfMemoryError参数
TCPCopy:网易出的一款软件,可以将线上生产环境的tcp拷贝一份到本地,一般用于线上流量压测本地环境
九、Arthas 开源 Java 诊断工具(阿里出的)
启动并将arthas挂载到我们的程序上
dbq@mac:~/Documents/tools/jvm性能诊断工具/arthas/arthas-packaging-3.1.1$ sh as.sh Arthas script version: 3.1.1 [INFO] JAVA_HOME: /Library/Java/JavaVirtualMachines/jdk1.8.0_131.jdk/Contents/Home Found existing java process, please choose one and hit RETURN. * [1]: 52193 org.jetbrains.jps.cmdline.Launcher [2]: 56573 com.mashibing.jvm.gc.TIS_FullGC_Problem01 [3]: 52142 2 Arthas home: /Users/dbq/Documents/tools/jvm性能诊断工具/arthas/arthas-packaging-3.1.1 Calculating attach execution time... Attaching to 56573 using version /Users/dbq/Documents/tools/jvm性能诊断工具/arthas/arthas-packaging-3.1.1... real 0m1.138s user 0m0.375s sys 0m0.052s Attach success. telnet connecting to arthas server... current timestamp is 1614413542 Trying 127.0.0.1... Connected to localhost. Escape character is '^]'. ,---. ,------. ,--------.,--. ,--. ,---. ,---. / O \ | .--. ''--. .--'| '--' | / O \ ' .-' | .-. || '--'.' | | | .--. || .-. |`. `-. | | | || |\ \ | | | | | || | | |.-' | `--' `--'`--' '--' `--' `--' `--'`--' `--'`-----' wiki https://alibaba.github.io/arthas tutorials https://alibaba.github.io/arthas/arthas-tutorials version 3.1.1 pid 56573 time 2021-02-27 16:12:22 $
dashboard命令:仪表盘,可以显示线程的情况
为了便于观察,我设置了线程名称
: $ thread 类似jstack
thread 线程号,可以把该线程的详细信息打出来
"GCTest-Thead" Id=1 TIMED_WAITING at java.lang.Thread.sleep(Native Method) at com.mashibing.jvm.gc.TIS_FullGC_Problem01.main(TIS_FullGC_Problem01.java:35) Affect(row-cnt:0) cost in 16 ms. $
thread -b: 可以查看是否有死锁
$ thread -b No most blocking thread found! Affect(row-cnt:0) cost in 18 ms. $
附录一(马士兵视频中的一些问题)
解决过哪些实际调优经验?
OOM