摘要: jvm monitor
$ top
top - 16:40:59 up 388 days, 1:04, 1 user, load average: 0.00, 0.01, 0.05
Tasks: 75 total, 1 running, 72 sleeping, 0 stopped, 2 zombie
%Cpu(s): 0.7 us, 0.3 sy, 0.0 ni, 99.0 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
KiB Mem : 1883492 total, 247312 free, 473204 used, 1162976 buff/cache
KiB Swap: 0 total, 0 free, 0 used. 1188144 avail Mem
$ uptime
16:42:36 up 388 days, 1:06, 1 user, load average: 0.00, 0.01, 0.05
其中 load average
代表的是cpu的平均负载,三个数字分别代表1分钟、5分钟、15分钟内cpu的平均负载。
负荷的大小跟cpu个数以及当前负荷有关系,例如1h 处理器,负载为5 则大概表面有1成的在running 4成的在等待,也就意味着此时可能服务器已经无法处理新的请求了,系统也就凉咯
查看cpu个数
$ cat /proc/cpuinfo | grep "cpu cores"
jstack
命令导出 9048 进程中线程栈的信息
$ jstack 9048 > 9048.txt
$ top -p 9048 -H # 拿到所有线程的cpu信息,定位具体线程pid
9243 root 20 0 2498028 59096 7008 S 91.0 3.1 0:00.00 java
9244 root 20 0 2498028 59096 7008 S 99.0 3.1 0:00.32 java
# 定位到线程pid为 9243 9244的cpu占用高
$ printf "%x" 9243 # 转为16进制--> 2353
$ printf "%x" 9244 # 转为16进制--> 2354
# 在9048.txt 查找nid为 0x2353 和 0x2354的线程栈信息,最后发现是nio的WindowsSelectorImpl导致的
$ cat 9048.txt
"http-nio-8499-ClientPoller-0" #27 daemon prio=5 os_prio=0 tid=0x4e69c800 nid=0x2353 runnable [0x5108f000]
java.lang.Thread.State: RUNNABLE
at sun.nio.ch.WindowsSelectorImpl.resetWakeupSocket0(Native Method)
at sun.nio.ch.WindowsSelectorImpl.resetWakeupSocket(Unknown Source)
- locked <0x257756d8> (a java.lang.Object)
at sun.nio.ch.WindowsSelectorImpl.doSelect(Unknown Source)
at sun.nio.ch.SelectorImpl.lockAndDoSelect(Unknown Source)
- locked <0x257756b8> (a sun.nio.ch.Util$2)
- locked <0x257756a8> (a java.util.Collections$UnmodifiableSet)
- locked <0x2575d518> (a sun.nio.ch.WindowsSelectorImpl)
at sun.nio.ch.SelectorImpl.select(Unknown Source)
at org.apache.tomcat.util.net.NioEndpoint$Poller.run(NioEndpoint.java:744)
at java.lang.Thread.run(Unknown Source)
Locked ownable synchronizers:
- None
打开 JDK 安装目录 bin 文件夹下的 jvisualvm.exe
,在左侧的本地下可以看到正常运行的java 应用,除了正常的类似命令行界面化的操作外,我们可以安装别的好用的插件
jvisualvm.exe
即可看到多出的 Visual GC Tab
Catalina.sh
文件JAVA_OPTS="$JAVA_OPTS -Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.port=xx -Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.ssl=false -Djava.net.preferlPv4Stack=true -Djava.rmi.server.hostname=xx.xx.xx.xx"
nohup java -Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.port=xx -Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.ssl=false -Djava.net.preferlPv4Stack=true -Djava.rmi.server.hostname=xx.xx.xx.xx -jar xx.jar &
Btrace可用动态的向目标应用程序的字节码注入追踪代码
https://github.com/btraceio/btrace
下载realse版本我这里是 v1.3.11.3
BTRACE_HOME
,Path 中追加 %BTRACE_HOME%\bin
JVisualVM
中添加Btrace插件,添加 classpath
btrace <pid> <trace_script>
这里举在JVisualVM
中使用的例子,安装完Btrace插件后,对其中的 java 应用列表右键打开Trace application,例如对某个应用的某个查询方法的脚本如下:
import com.sun.btrace.AnyType;
import com.sun.btrace.BTraceUtils;
import com.sun.btrace.annotations.BTrace;
import com.sun.btrace.annotations.Kind;
import com.sun.btrace.annotations.Location;
import com.sun.btrace.annotations.OnMethod;
import com.sun.btrace.annotations.ProbeClassName;
import com.sun.btrace.annotations.ProbeMethodName;
@BTrace
public class PrintArgDemo {
@OnMethod(
clazz="com.clamc.climb.admin.web.UserController",
method="query",
location=@Location(Kind.ENTRY)
)
public static void queryTest(@ProbeClassName String className, @ProbeMethodName String methodName, AnyType[] args) {
BTraceUtils.printArray(args);
BTraceUtils.println(className + " " + methodName);
BTraceUtils.println();
}
}
勾上 Output
Class-Path
(Class-Path 可以用来增加第三方jar包),点击 Start
即可等待执行到 query
方法后的打印输出