Java 调试技巧

2023-11-20 14:45:51 浏览数 (1)

Java 调试技巧

1、IDEA 远程调试代码

在 idea 项目配置当中添加一个 Remote JVM debug,当然每个 idea 版本可能名称不一致,看准图标就行。

然后配置远程服务器的地址,复制 Command line argumengts for remote JVM 下面的命令行。

然后将项目打包,启动的时候添加上面复制的命令行。比如运行的命令是这样的:java -jar -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5005 test.jar

启动了远程项目,就可以本地运行调试配置了。建议不要直接调试线上项目,复制一个项目副本去调试,不然会阻塞所有线程,实在要调试的话可以配合条件调试加线程级的阻塞来测试。

2、jstack 调试

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

语法

代码语言:text复制
Usage:  
    jstack [-l] <pid>  
        连接正常运行的进程  
        (to connect to running process)  
    jstack -F [-m] [-l] <pid>  
        连接挂起的进程  
        (to connect to a hung process)  
    jstack [-m] [-l] <executable> <core>  
        (to connect to a core file)  
    jstack [-m] [-l] [server_id@]<remote server IP or hostname>  
        连接远程服务器  
        (to connect to a remote debug server)  
  
Options:  
    -F  to force a thread dump. Use when jstack <pid> does not respond (process is hung)  当使用 jstack <pid> 没有响应时强制打印堆栈  
    -m  to print both java and native frames (mixed mode) 打印 java 和 native 的堆栈  
    -l  long listing. Prints additional information about locks 打印锁持有信息  
    -h or -help to print this help message  

使用 jstack 111 获取堆栈信息

代码语言:css复制
"http-nio-7676-Acceptor" #37 daemon prio=5 os_prio=0 tid=0x0000000021947000 nid=0x1610 runnable [0x0000000027f7e000]  
   java.lang.Thread.State: RUNNABLE  
        at sun.nio.ch.ServerSocketChannelImpl.accept0(Native Method)  
        at sun.nio.ch.ServerSocketChannelImpl.accept(Unknown Source)  
        at sun.nio.ch.ServerSocketChannelImpl.accept(Unknown Source)  
        - locked <0x0000000770fa58b0> (a java.lang.Object)  
        at org.apache.tomcat.util.net.NioEndpoint.serverSocketAccept(NioEndpoint.java:547)  
        at org.apache.tomcat.util.net.NioEndpoint.serverSocketAccept(NioEndpoint.java:79)  
        at org.apache.tomcat.util.net.Acceptor.run(Acceptor.java:129)  
        at java.lang.Thread.run(Unknown Source)  

线程名称:http-nio-7676-Acceptor

线程类型:守护线程 daemon,还有个 non-daemon 非守护线程

线程优先级:prio=5

JVM 线程ID:tid=0x0000000021947000,JVM内部线程的唯一标识,通过 java.lang.Thread.getId()获取,通常用自增的方式实现

系统线程ID:nid=0x1610,16 进制形式。线程ID。win10中的是 TID。

系统线程状态:runnable

起始栈地址:[0x0000000027f7e000]

JVM 线程状态:RUNNABLE

下面的就是线程调用栈信息了,最下面的是线程开始调用的位置,最后是结束调用的位置。

系统线程状态

代码语言:shell复制
deadlock  
死锁线程,一般指多个线程调用期间进入了相互资源占用,导致一直等待无法释放的情况。  
  
runnable  
一般指该线程正在执行状态中,该线程占用了资源,正在处理某个操作,如通过SQL语句查询数据库、对某个文件进行写入等。  
  
blocked  
线程正处于阻塞状态,指当前线程执行过程中,所需要的资源长时间等待却一直未能获取到,被容器的线程管理器标识为阻塞状态,可以理解为等待资源超时的线程。  
  
waiting on condition  
线程正处于等待资源或等待某个条件的发生,具体的原因需要结合下面堆栈信息进行分析。  
  
(1)如果堆栈信息明确是应用代码,则证明该线程正在等待资源,一般是大量读取某种资源且该资源采用了资源锁的情况下,线程进入等待状态,等待资源的读取,或者正在等待其他线程的执行等。  
  
(2)如果发现有大量的线程都正处于这种状态,并且堆栈信息中得知正等待网络读写,这是因为网络阻塞导致线程无法执行,很有可能是一个网络瓶颈的征兆:  
  
网络非常繁忙,几乎消耗了所有的带宽,仍然有大量数据等待网络读写;  
网络可能是空闲的,但由于路由或防火墙等原因,导致包无法正常到达;  
所以一定要结合系统的一些性能观察工具进行综合分析,比如netstat统计单位时间的发送包的数量,看是否很明显超过了所在网络带宽的限制;观察CPU的利用率,看系统态的CPU时间是否明显大于用户态的CPU时间。这些都指向由于网络带宽所限导致的网络瓶颈。  
  
(3)还有一种常见的情况是该线程在 sleep,等待 sleep 的时间到了,将被唤醒。  
  
Object.wait(),对象等待中  
waiting for monitor entry 等待获取监视器  

JVM线程状态

代码语言:text复制
NEW  
至今尚未启动的线程的状态。线程刚被创建,但尚未启动。  
  
RUNNABLE  
可运行线程的线程状态。线程正在JVM中执行,有可能在等待操作系统中的其他资源,比如处理器。  
  
BLOCKED  
受阻塞并且正在等待监视器的某一线程的线程状态。处于受阻塞状态的某一线程正在等待监视器锁,以便进入一个同步的块/方法,或者在调用 Object.wait 之后再次进入同步的块/方法。  
在Thread Dump日志中通常显示为 java.lang.Thread.State: BLOCKED (on object monitor) 。  
  
WAITING  
某一等待线程的线程状态。线程正在无期限地等待另一个线程来执行某一个特定的操作,线程因为调用下面的方法之一而处于等待状态:  
  
不带超时的 Object.wait 方法,日志中显示为 java.lang.Thread.State: WAITING (on object monitor)  
不带超时的 Thread.join 方法  
LockSupport.park 方法,日志中显示为 java.lang.Thread.State: WAITING (parking)  
TIMED_WAITING  
指定了等待时间的某一等待线程的线程状态。线程正在等待另一个线程来执行某一个特定的操作,并设定了指定等待的时间,线程因为调用下面的方法之一而处于定时等待状态:  
  
Thread.sleep 方法  
指定超时值的 Object.wait 方法  
指定超时值的 Thread.join 方法  
LockSupport.parkNanos  
LockSupport.parkUntil   
TERMINATED  
线程处于终止状态。  
  
根据Java Doc中的说明,在给定的时间上,一个只能处于上述的一种状态之中,并且这些状态都是JVM的状态,跟操作系统中的线程状态无关。  

死锁分析

代码语言:scss复制
@RestController  
public class TestController {  
  
    final String str1 = "哈哈".intern();  
    final String str2 = "哈哈2".intern();  
  
    @GetMapping("test")  
    public void test(){  
        test1();  
    }  
  
    public void test1(){  
        synchronized (str1){  
            System.out.println(1);  
            new Thread(()->{  
                test2();  
            }).start();  
            try {  
                Thread.sleep(2000);  
            } catch (InterruptedException e) {  
                e.printStackTrace();  
            }  
            synchronized (str2){  
                System.out.println(2);  
            }  
        }  
    }  
  
    public void test2(){  
        synchronized (str2){  
            System.out.println(3);  
            synchronized (str1){  
                System.out.println(4);  
            }  
        }  
    }  
}  
  

test1 方法先获取到 str1 锁,然后新开一个线程去执行 test2 方法,test2 方法获取 str2 锁之后,然后尝试获取 str1 锁,但是 str1 锁因为 test1 方法休眠了两秒还未释放 str1 的锁,所以造成 test2 方法等待 str1 锁的释放,test1 休眠结束后,尝试获取 str2 锁,但是因为 test2 方法在等待 str1 释放没有释放 str2 锁。经典的锁互相持有问题。

使用 jstack -l 1 获取一下锁的信息:

代码语言:php复制
"Thread-2" #39 daemon prio=5 os_prio=0 tid=0x000000002201d000 nid=0x1bbc waiting for monitor entry [0x0000000028aaf000]  
   java.lang.Thread.State: BLOCKED (on object monitor)  
        at com.example.testdebugs.controller.TestController.test2(TestController.java:38)  
        - waiting to lock <0x0000000773cb83e0> (a java.lang.String)  
        - locked <0x0000000773cb8410> (a java.lang.String)  
        at com.example.testdebugs.controller.TestController.lambda$test1$0(TestController.java:21)  
        at com.example.testdebugs.controller.TestController$$Lambda$587/128287643.run(Unknown Source)  
        at java.lang.Thread.run(Unknown Source)  
  
   Locked ownable synchronizers:  
        - None  
  
  
  
"http-nio-7676-exec-1" #26 daemon prio=5 os_prio=0 tid=0x0000000026a22800 nid=0x5b68 waiting for monitor entry [0x0000000027a6c000]  
   java.lang.Thread.State: BLOCKED (on object monitor)  
        at com.example.testdebugs.controller.TestController.test1(TestController.java:29)  
        - waiting to lock <0x0000000773cb8410> (a java.lang.String)  
        - locked <0x0000000773cb83e0> (a java.lang.String)  
        at com.example.testdebugs.controller.TestController.test(TestController.java:14)  
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)  
        at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)  
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)  
        at java.lang.reflect.Method.invoke(Unknown Source)  
        at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:205)  
        at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:150)  
        at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:117)  
        at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:895)  
        at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:808)  
        at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87)  
        at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1071)  
        at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:964)  
        at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006)  
        at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:898)  
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:670)  
        at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883)  
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:779)  
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:227)  
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)  
        at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)  
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)  
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)  
        at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100)  
        at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117)  
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)  
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)  
        at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93)  
        at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117)  
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)  
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)  
        at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201)  
        at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117)  
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)  
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)  
        at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:177)  
        at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:97)  
        at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:541)  
        at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:135)  
        at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92)  
        at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:78)  
        at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:360)  
        at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:399)  
        at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65)  
        at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:891)  
        at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1784)  
        at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)  
        - locked <0x0000000773936ba0> (a org.apache.tomcat.util.net.NioEndpoint$NioSocketWrapper)  
        at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1191)  
        at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659)  
        at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)  
        at java.lang.Thread.run(Unknown Source)  
  
   Locked ownable synchronizers:  
        - <0x00000007739a9ec0> (a org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker)  
  
  
  
Found one Java-level deadlock:  
=============================  
"Thread-2":  
  waiting to lock monitor 0x000000001d515458 (object 0x0000000773cb83e0, a java.lang.String),  
  which is held by "http-nio-7676-exec-1"  
"http-nio-7676-exec-1":  
  waiting to lock monitor 0x000000001d512c78 (object 0x0000000773cb8410, a java.lang.String),  
  which is held by "Thread-2"  
  
Java stack information for the threads listed above:  
===================================================  
"Thread-2":  
        at com.example.testdebugs.controller.TestController.test2(TestController.java:38)  
        - waiting to lock <0x0000000773cb83e0> (a java.lang.String)  
        - locked <0x0000000773cb8410> (a java.lang.String)  
        at com.example.testdebugs.controller.TestController.lambda$test1$0(TestController.java:21)  
        at com.example.testdebugs.controller.TestController$$Lambda$587/128287643.run(Unknown Source)  
        at java.lang.Thread.run(Unknown Source)  
"http-nio-7676-exec-1":  
        at com.example.testdebugs.controller.TestController.test1(TestController.java:29)  
        - waiting to lock <0x0000000773cb8410> (a java.lang.String)  
        - locked <0x0000000773cb83e0> (a java.lang.String)  
        at com.example.testdebugs.controller.TestController.test(TestController.java:14)  
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)  
        at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)  
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)  
        at java.lang.reflect.Method.invoke(Unknown Source)  
        at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:205)  
        at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:150)  
        at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:117)  
        at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:895)  
        at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:808)  
        at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87)  
        at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1071)  
        at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:964)  
        at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006)  
        at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:898)  
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:670)  
        at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883)  
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:779)  
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:227)  
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)  
        at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)  
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)  
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)  
        at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100)  
        at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117)  
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)  
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)  
        at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93)  
        at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117)  
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)  
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)  
        at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201)  
        at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117)  
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)  
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)  
        at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:177)  
        at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:97)  
        at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:541)  
        at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:135)  
        at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92)  
        at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:78)  
        at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:360)  
        at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:399)  
        at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65)  
        at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:891)  
        at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1784)  
        at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)  
        - locked <0x0000000773936ba0> (a org.apache.tomcat.util.net.NioEndpoint$NioSocketWrapper)  
        at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1191)  
        at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659)  
        at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)  
        at java.lang.Thread.run(Unknown Source)  
  
Found 1 deadlock.  

CPU占用率高分析

这个其中就是上面的反向分析,使用 top 找出线程占用最高的程序,然后转换成十六进制形式。在 jstack 信息中找到对应的线程,查看调用线程栈,就能知道哪块代码有问题了。

3、jmap 调试

jmap(Java Virtual Machine Memory Map)是 JDK 提供的一个可以生成 Java 虚拟机的堆转储快照 dump 文件的命令行工具。

语法

代码语言:text复制
Usage:  
    jmap [option] <pid>  
        (to connect to running process) 连接正在运行的进程  
    jmap [option] <executable <core>  
        (to connect to a core file)  
    jmap [option] [server_id@]<remote server IP or hostname>  
        (to connect to remote debug server) 连接远程线程  
  
where <option> is one of:  
    <none>               to print same info as Solaris pmap  
    -heap                to print java heap summary 打印 Java 堆栈简要  
    -histo[:live]        to print histogram of java object heap; if the "live" 打印 Java 堆中对象的统计信息,如果指定了 live 参数,则只打印活动对象  
                         suboption is specified, only count live objects  
    -clstats             to print class loader statistics 打印 class loader 的统计信息  
    -finalizerinfo       to print information on objects awaiting finalization 打印 F-Queue 中等待 Finalizer 线程执行 finalize 方法的对象  
    -dump:<dump-options> to dump java heap in hprof binary format 生成Java虚拟机的堆转储快照dump文件  
                         dump-options:  
                           live         dump only live objects; if not specified,  
                                        all objects in the heap are dumped.  
                           format=b     binary format  
                           file=<file>  dump heap to <file>  
                         Example: jmap -dump:live,format=b,file=heap.bin <pid>  
    -F                   force. Use with -dump:<dump-options> <pid> or -histo  
                         to force a heap dump or histogram when <pid> does not  
                         respond. The "live" suboption is not supported  
                         in this mode.  
    -h | -help           to print this help message  
    -J<flag>             to pass <flag> directly to the runtime system  

jmap -heap 1

代码语言:text复制
using thread-local object allocation.  
Parallel GC with 13 thread(s)  
  
Heap Configuration:  
   MinHeapFreeRatio         = 0 空闲堆空间的最小百分比,计算公式为:HeapFreeRatio =(CurrentFreeHeapSize/CurrentTotalHeapSize) * 100  
   MaxHeapFreeRatio         = 100 空闲堆空间的最大百分比  
   MaxHeapSize              = 4223664128 (4028.0MB) JVM 堆空间允许的最大值。  
   NewSize                  = 88080384 (84.0MB) JVM 新生代堆空间的默认值。  
   MaxNewSize               = 1407713280 (1342.5MB) JVM 新生代堆空间允许的最大值。  
   OldSize                  = 176160768 (168.0MB) JVM 老年代堆空间的默认值。  
   NewRatio                 = 2 新生代(2个Survivor区和Eden区 )与老年代(不包括永久区)的堆空间比值,表示新生代:老年代=1:2。  
   SurvivorRatio            = 8 两个Survivor区和Eden区的堆空间比值为 8,表示 S0 : S1 :Eden = 1:1:8。  
   MetaspaceSize            = 21807104 (20.796875MB) JVM 元空间的默认值。  
   CompressedClassSpaceSize = 1073741824 (1024.0MB)  
   MaxMetaspaceSize         = 17592186044415 MB JVM 元空间允许的最大值。  
   G1HeapRegionSize         = 0 (0.0MB) 在使用 G1 垃圾回收算法时,JVM 会将 Heap 空间分隔为若干个 Region,该参数用来指定每个 Region 空间的大小。  
  
Heap Usage:  
PS Young Generation  
Eden Space:  
   capacity = 88080384 (84.0MB) 空间大小  
   used     = 83642848 (79.76803588867188MB) 使用空间  
   free     = 4437536 (4.231964111328125MB) 空闲空间  
   94.96194748651413% used 使用率  
From Space:  
   capacity = 3670016 (3.5MB)  
   used     = 3162744 (3.0162277221679688MB)  
   free     = 507272 (0.48377227783203125MB)  
   86.17793491908482% used  
To Space:  
   capacity = 11010048 (10.5MB)  
   used     = 0 (0.0MB)  
   free     = 11010048 (10.5MB)  
   0.0% used  
PS Old Generation  
   capacity = 114294784 (109.0MB)  
   used     = 6119576 (5.836082458496094MB)  
   free     = 108175208 (103.1639175415039MB)  
   5.354204090363389% used  
  
14131 interned Strings occupying 1297968 bytes.  

jmap -histo 1

代码语言:text复制
 num     #instances         #bytes  class name  
----------------------------------------------  
   1:        289211       48424824  [C  
   2:         22184       16519992  [B  
   3:         15093        4970888  [I  
   4:        193772        4650528  java.lang.String  
   5:         27302        1747328  java.net.URL  
   6:         20163        1315544  [Ljava.lang.Object;  
   7:          9967         877096  java.lang.reflect.Method  
   8:         26036         833152  org.springframework.boot.loader.jar.StringSequence  
   9:         37770         781224  [Ljava.lang.Class;  
  10:          6534         722976  java.lang.Class  
  
StringSequence 对象有 26036 个,占用 833152 字节,可以使用 jmap -histo:live 1 查看活动对象的统计  

jmap -clstats 1

代码语言:text复制
  
class_loader    classes bytes   parent_loader   alive?  type  
  
<bootstrap>     1898    3329718   null          live    <internal>  
0x00000006c4b104b0      1       1472    0x00000006c4439478      dead    sun/reflect/DelegatingClassLoader@0x00000007c000a028  
0x00000006c4b10a30      1       1472    0x00000006c4439478      dead    sun/reflect/DelegatingClassLoader@0x00000007c000a028  
0x00000006c4422e80      1       1472    0x00000006c4439478      dead    sun/reflect/DelegatingClassLoader@0x00000007c000a028  
0x00000006c4cea7c8      1       1471    0x00000006c4439478      dead    sun/reflect/DelegatingClassLoader@0x00000007c000a028  
0x00000006c4b10578      1       1472      null          dead    sun/reflect/DelegatingClassLoader@0x00000007c000a028  
0x00000006c4b10af8      1       880       null          dead    sun/reflect/DelegatingClassLoader@0x00000007c000a028  
0x00000006c4423148      1       1472      null          dead    sun/reflect/DelegatingClassLoader@0x00000007c000a028  
0x00000006c4cea180      1       1472    0x00000006c4439478      dead    sun/reflect/DelegatingClassLoader@0x00000007c000a028  
0x00000006c4cea700      1       1472    0x00000006c4439478      dead    sun/reflect/DelegatingClassLoader@0x00000007c000a028  
0x00000006c4971ed8      0       0       0x00000006c4439478      live    org/springframework/boot/web/embedded/tomcat/TomcatEmbeddedWebappClassLoader@0x00000007c038fc18  
0x00000006c4b10820      1       880       null          dead    sun/reflect/DelegatingClassLoader@0x00000007c000a028  
0x00000006c4424e10      1       1472      null          dead    sun/reflect/DelegatingClassLoader@0x00000007c000a028  
0x00000006c4cea558      1       1471    0x00000006c4439478      dead    sun/reflect/DelegatingClassLoader@0x00000007c000a028  
0x00000006c4407158      47      80508   0x00000006c44071b8      live    sun/misc/Launcher$AppClassLoader@0x00000007c000f8d8  
0x00000006c4b0e3a8      1       1472    0x00000006c4439478      dead    sun/reflect/DelegatingClassLoader@0x00000007c000a028  
0x00000006c4b103e8      1       1472    0x00000006c4439478      dead    sun/reflect/DelegatingClassLoader@0x00000007c000a028  
0x00000006c4b108e8      1       1472    0x00000006c4439478      dead    sun/reflect/DelegatingClassLoader@0x00000007c000a028  
0x00000006c4859258      0       0       0x00000006c4407158      live    java/util/ResourceBundle$RBClassLoader@0x00000007c00bbe10  
0x00000006c4ceafa8      1       1471    0x00000006c4439478      dead    sun/reflect/DelegatingClassLoader@0x00000007c000a028  
0x00000006c4b10758      1       1472    0x00000006c4439478      dead    sun/reflect/DelegatingClassLoader@0x00000007c000a028  
0x00000006c4b11dd8      1       1471      null          dead    sun/reflect/DelegatingClassLoader@0x00000007c000a028  
0x00000006c4cea620      1       1472    0x00000006c4439478      dead    sun/reflect/DelegatingClassLoader@0x00000007c000a028  
0x00000006c4b0fac0      1       880       null          dead    sun/reflect/DelegatingClassLoader@0x00000007c000a028  
0x00000006c4b10d40      1       1472    0x00000006c4439478      dead    sun/reflect/DelegatingClassLoader@0x00000007c000a028  
0x00000006c4ceb238      1       1471    0x00000006c4439478      dead    sun/reflect/DelegatingClassLoader@0x00000007c000a028  
0x00000006c44071b8      13      17876     null          live    sun/misc/Launcher$ExtClassLoader@0x00000007c000fc80  
0x00000006c4b10308      1       1472      null          dead    sun/reflect/DelegatingClassLoader@0x00000007c000a028  
0x00000006c4422db8      1       1472      null          dead    sun/reflect/DelegatingClassLoader@0x00000007c000a028  
0x00000006c4439478      3323    5338474 0x00000006c4407158      live    org/springframework/boot/loader/LaunchedURLClassLoader@0x00000007c0060828  
0x00000006c4ceb070      1       1471    0x00000006c4439478      dead    sun/reflect/DelegatingClassLoader@0x00000007c000a028  
  
total = 31      5306    8801594     N/A         alive=6, dead=25            N/A  
  
class_loader:当Java虚拟机运行时,类加载器对象的地址  
classes:已加载类的数量  
bytes:该类加载器加载的所有类的元数据所占的字节数  
parent_loader:父类加载器对象的地址,如果没有显示null。  
alive:是否存活的标识,表示类加载器对象是否将被垃圾回收。  
type:该类加载器的类名。  
4、jstat 工具调试

主要利用JVM内建的指令对Java应用程序的资源和性能进行实时的命令行的监控,包括了对Heap size和垃圾回收状况的监控。

相较于 jmap,jstat显示的是简略的信息,查看具体信息还是看 jmap。

语法

代码语言:text复制
  
Usage: jstat -help|-options  
       jstat -<option> [-t] [-h<lines>] <vmid> [<interval> [<count>]]  
  
-t:可以在打印的列加上Timestamp列,用于显示系统运行的时间  
-h:可以在周期性数据输出的时候,指定输出多少行以后输出一次表头  
vmid:Virtual Machine ID( 进程的 pid)  
interval:执行每次的间隔时间,单位为毫秒  
count:用于指定输出多少次记录,缺省则会一直打印  
  
  
Definitions:  
  <option>      An option reported by the -options option  
  <vmid>        Virtual Machine Identifier. A vmid takes the following form:  
                     <lvmid>[@<hostname>[:<port>]]  
                Where <lvmid> is the local vm identifier for the target  
                Java virtual machine, typically a process id; <hostname> is  
                the name of the host running the target Java virtual machine;  
                and <port> is the port number for the rmiregistry on the  
                target host. See the jvmstat documentation for a more complete  
                description of the Virtual Machine Identifier.  
  <lines>       Number of samples between header lines.  
  <interval>    Sampling interval. The following forms are allowed:  
                    <n>["ms"|"s"]  
                Where <n> is an integer and the suffix specifies the units as  
                milliseconds("ms") or seconds("s"). The default units are "ms".  
  <count>       Number of samples to take before terminating.  
  -J<flag>      Pass <flag> directly to the runtime system.  
  
option:  
  
-class  用于查看类加载情况的统计  
-compiler 用于查看HotSpot中即时编译器编译情况的统计  
-gc 用于查看JVM中堆的垃圾收集情况的统计  
-gccapacity 用于查看新生代、老生代及持久代的存储容量情况  
-gccause 显示垃圾回收的相关信息(通-gcutil),同时显示最后一次仅当前正在发生的垃圾收集的原因  
-gcmetacapacity 显示metaspace的大小   
-gcnew 用于查看新生代垃圾收集的情况  
-gcnewcapacity 用于查看新生代存储容量的情况  
-gcold 用于查看老生代及持久代垃圾收集的情况  
-gcoldcapacity  用于查看老生代的容量  
-gcutil 显示垃圾收集信息  
-printcompilation 输出JIT编译的方法信息  

jstat -class 1

代码语言:text复制
Loaded  Bytes  Unloaded  Bytes     Time  
  6059 11049.9        0     0.0       1.17  
  
Loaded:加载类的数量  
Bytes:加载类的size,单位为Byte  
Unloaded:卸载类的数目  
Bytes:卸载类的size,单位为Byte  
Time:加载与卸载类花费的时间  
5、jinfo

jinfo 是 Java 虚拟机自带的 Java 配置信息工具,可以实时地查看和调整虚拟机的各项参数。

参数只有被标记 manageable 的 flag 可以被实时修改

语法

代码语言:text复制
Usage:  
    jinfo [option] <pid>  
        (to connect to running process)  
    jinfo [option] <executable <core>  
        (to connect to a core file)  
    jinfo [option] [server_id@]<remote server IP or hostname>  
        (to connect to remote debug server)  
  
where <option> is one of:  
    -flag <name>         to print the value of the named VM flag 打印 name 值  
    -flag [ |-]<name>    to enable or disable the named VM flag 启用或者禁用 name 值  
    -flag <name>=<value> to set the named VM flag to the given value name参数赋新值  
    -flags               to print VM flags 打印所有参数  
    -sysprops            to print Java system properties 打印 java 系统参数  
    <no option>          to print both of the above  
    -h | -help           to print this help message  
6、可视化工具 jconsole

命令行输入 jconsole。可视化工具其实是上面工具的整合。

7、可视化工具 jvisualvm

命令行输入 jvisualvm。

我正在参与2023腾讯技术创作特训营第三期有奖征文,组队打卡瓜分大奖!

0 人点赞