Java--定位问题工具

JVM规范定义的内存结构
在这里插入图片描述
java8已经没有了方法区这个概念,改为了metaspace,存储字符串常量池、静态变量。
Java8的内存结果
在这里插入图片描述

jps (JVM process status)可以查看Java虚拟机进程执行情况,-l显示具体的启动类,-m显示具体的入参。-v显示启动配置的jvm参数

jps -l

在这里插入图片描述

jstats(JVM statistic Monitoring tool):查看虚拟机上各项运行状态信息。
查看虚拟机号为5640的gc情况。

jstat -gc 5640 100

在这里插入图片描述

 S0C    S1C    S0U    S1U      EC       EU        OC         OU       MC     MU    CCSC   CCSU   YGC     YGCT    FGC    FGCT     GCT   
2560.0 2560.0  0.0    0.0   15360.0   3696.2   40960.0      0.0     4480.0 774.9  384.0   75.9       0    0.000   0      0.000    0.000
2560.0 2560.0  0.0    0.0   15360.0   3696.2   40960.0      0.0     4480.0 774.9  384.0   75.9       0    0.000   0      0.000    0.000
2560.0 2560.0  0.0    0.0   15360.0   3696.2   40960.0      0.0     4480.0 774.9  384.0   75.9       0    0.000   0      0.000    0.000
2560.0 2560.0  0.0    0.0   15360.0   3696.2   40960.0      0.0     4480.0 774.9  384.0   75.9       0    0.000   0      0.000    0.000
2560.0 2560.0  0.0    0.0   15360.0   3696.2   40960.0      0.0     4480.0 774.9  384.0   75.9       0    0.000   0      0.000    0.000
2560.0 2560.0  0.0    0.0   15360.0   3696.2   40960.0      0.0     4480.0 774.9  384.0   75.9       0    0.000   0      0.000    0.000
2560.0 2560.0  0.0    0.0   15360.0   3696.2   40960.0      0.0     4480.0 774.9  384.0   75.9       0    0.000   0      0.000    0.000
2560.0 2560.0  0.0    0.0   15360.0   3696.2   40960.0      0.0     4480.0 774.9  384.0   75.9       0    0.000   0      0.000    0.000
2560.0 2560.0  0.0    0.0   15360.0   3696.2   40960.0      0.0     4480.0 774.9  384.0   75.9       0    0.000   0      0.000    0.000
2560.0 2560.0  0.0    0.0   15360.0   3696.2   40960.0      0.0     4480.0 774.9  384.0   75.9       0    0.000   0      0.000    0.000

S0C S1C S0U S1U survivor0和survivor1
EC EU 新生代 总量和使用
OC OU 老生代 总量和使用
MC MU metaspace 总量和使用
CCSC CCSU 压缩类总量和使用
YGC YGCT younggc的次数和时间
FGC FGCT Full的次数和时间
GCT 总的gc时间

jinfo:查看和调整虚拟机的各项参数

jinfo -flag

如查看是否使用了UseSerial垃圾回收器

jinfo -flag UseSerialGC 5640

在这里插入图片描述
使用的减号,那么没用用UseSerial收集器。

查看所有的jvm参数

jinfo -flags 7395
Attaching to process ID 7395, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 25.101-b13
Non-default VM flags: -XX:CICompilerCount=4 -XX:InitialHeapSize=262144000 -XX:MaxHeapSize=4164943872 -XX:MaxNewSize=1388314624 -XX:MinHeapDeltaBytes=524288 -XX:NewSize=87031808 -XX:OldSize=175112192 -XX:+UseCompressedClassPointers -XX:+UseCompressedOops -XX:+UseParallelGC
Command line:  -Dspring.config.location=application-pro.yml -Dspring.profiles.active=pro

jmap(JVM Memory Map For Java):生成堆内存快照,

jmap -dump:format=b,file=jmapDumpFile 3137

也可以在出现内存溢出后自动生成dump文件。利用jdk目录下\jdk1.8.0_144\bin提供的jvisualvm.exe打开。jvisualvm.exe同时支持在线监控,
定位频繁gc测试代码

    @GetMapping("/oom")
    public Integer oom(){
        final Thread thread = new Thread(new Runnable() {
            @Override
            public void run() {
                List<User> userList = new ArrayList<>();
                for (int i = 0; i < 1000 * 10000; i++) {
                    User user = new User();
                    user.setId(i);
                    user.setUserName("u" + i);
                    user.setPassword("123");
                    user.setCreateTime(new Date());
                    user.setExp1("");
                    user.setExp2("");
                    user.setExp3("");
                    user.setExp4("");
                    user.setExp5("");
                    user.setExp6("");
                    user.setExp7("");
                    user.setExp8("");
                    user.setExp9("");
                    user.setExp10("");
                    user.setExp11("");
                    user.setExp12("");
                    user.setExp13("");
                    user.setExp14("");
                    user.setExp15("");
                    user.setExp16("");
                    user.setExp17("");
                    user.setExp18("");
                    user.setExp19("");
                    user.setExp20("");
                    userList.add(user);
                }
                try {
                    Thread.sleep(10000000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
        thread.setName("测试线程");
        thread.start();
        return 1;
    }

调整jvm执行时的最大内存

-Xmx1024m 

执行如上的耗时代码,在jvisualvm.exe可看到如下图选。
在这里插入图片描述
普通不耗时的请求也无法处理。

Exception in thread "测试线程" java.lang.OutOfMemoryError: GC overhead limit exceeded
	at java.util.Arrays.copyOfRange(Arrays.java:3664)
	at java.lang.String.<init>(String.java:207)
	at java.lang.StringBuilder.toString(StringBuilder.java:407)
	at com.test.controller.UserController$3.run(UserController.java:76)
	at java.lang.Thread.run(Thread.java:748)
2021-01-18 17:04:49.049  WARN 5956 --- [MI TCP Accept-0] sun.rmi.transport.tcp                    : RMI TCP Accept-0: accept loop for ServerSocket[addr=0.0.0.0/0.0.0.0,localport=54683] throws

java.lang.OutOfMemoryError: GC overhead limit exceeded
	at java.net.NetworkInterface.getAll(Native Method) ~[na:1.8.0_131]
	at java.net.NetworkInterface.getNetworkInterfaces(NetworkInterface.java:343) ~[na:1.8.0_131]
	at sun.management.jmxremote.LocalRMIServerSocketFactory$1.accept(LocalRMIServerSocketFactory.java:86) ~[na:1.8.0_131]
	at sun.rmi.transport.tcp.TCPTransport$AcceptLoop.executeAcceptLoop(TCPTransport.java:400) [na:1.8.0_131]
	at sun.rmi.transport.tcp.TCPTransport$AcceptLoop.run(TCPTransport.java:372) [na:1.8.0_131]
	at java.lang.Thread.run(Thread.java:748) [na:1.8.0_131]

点击jvisualvm.exe生成dump文件。使用momery analyzer分析
在这里插入图片描述
显示一个线程生成了太多本地变量,查看stacktrace信息
在这里插入图片描述
可以查看到具体的堆栈信息。

jhat(JVM Heap Analysis Tool)分析jmap生成的堆内存快照。

jhat jmapDumpFile

显示Server is ready后在浏览器中输入http://192.168.209.101:7000查看结果
一帮查询堆内存中总容量最大的对象。
在这里插入图片描述

jstack:生成线程执行的栈信息,定位线程出现长时间停顿的原因

jstack -l 3137

生成线程dump文件,用jvisualvm.exe打开。

jstack -l 3137 >> thread.tdump

JDK目录\jdk1.8.0_144\bin下提供了图形化的界面显示内存、线程执行情况的工具jconsole.exe,进入之前选择对应的虚拟机即可。
在这里插入图片描述
如果出现空循环的问题,可通过堆栈查看出来
测试代码:

    public static void main(String[] args) throws InterruptedException {
        Thread thread=new Thread(new Runnable() {
            @Override
            public void run() {
                while (true){

                }
            }
        },"testBusyThread");
        thread.start();
        
        Thread.sleep(1000000);
    }

在这里插入图片描述

定位线上CPU使用率过高的问题。
模拟该场景,在main函数中写个死循环,使用top命令得到该进程id。
在这里插入图片描述
使用jps -l查询得到是那个项目
在这里插入图片描述
如下命令得到占用的线程

ps -mp 2050 -o THREAD,tid,time

time为占用的时间,tid为线程id
在这里插入图片描述
-m显示所有的线程
-p pid进程使用cpu的时间
-o 使用用户自定义的格式。
或者用如下命令

top -Hp 17583

在这里插入图片描述
上图中的pid即为线程id。

占用的线程为2051,需要转换为16进制。

printf "%x\n" 2051

得到803,如果出现16进制数为字母,需要转为小写。

如下命令得到具体那个线程

jstack 2050 |grep 803 -A60

整体流程为:
1 通过 t o p 得到占用过高的进程 i d \color{#FF0000}{1 通过top得到占用过高的进程id} 1通过top得到占用过高的进程id
2 通过 p s − m p 得到占用过高的线程 i d \color{#FF0000}{2 通过ps -mp得到占用过高的线程id} 2通过psmp得到占用过高的线程id
3 通过 j s t a c k 进程 i d 得到线程快照,从快照中 g r e p 那个线程 i d ,即可得到具体是那个线程执行的那个代码块 \color{#FF0000}{3 通过jstack 进程id得到线程快照,从快照中grep那个线程id,即可得到具体是那个线程执行的那个代码块} 3通过jstack进程id得到线程快照,从快照中grep那个线程id,即可得到具体是那个线程执行的那个代码块

部分摘自某课网

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值