一、参照地址:https://blog.csdn.net/HO1_K/article/details/127883411
JVM监控及诊断工具-命令行篇 - 知乎 (zhihu.com)
垃圾回收:JVM的垃圾回收机制——垃圾回收算法 - 知乎 (zhihu.com)、图文并茂,万字详解,带你掌握 JVM 垃圾回收! - 知乎 (zhihu.com)
1、查看JVM默认参数:java -XX:+PrintCommandLineFlags -version
C:\Users\namejr>java -XX:+PrintCommandLineFlags -version -XX:InitialHeapSize=266524864 -XX:MaxHeapSize=4264397824 -XX:+PrintCommandLineFlags -XX:+UseCompressedClassPointers -XX:+UseCompressedOops -XX:-UseLargePagesIndividualAllocation -XX:+UseParallelGC java version "1.8.0_201" Java(TM) SE Runtime Environment (build 1.8.0_201-b09) Java HotSpot(TM) 64-Bit Server VM (build 25.201-b09, mixed mode)
-XX:InitialHeapSize:堆内存初始值(内存单位:默认(byte)、K(kb)、M(mb)、G(gb),后续内存单位不再累述);-XX:MaxHeapSize:堆内存最大值;-XX:+PrintCommandLineFlags :打印虚拟机的显示和隐藏参数;
参照:https://zhuanlan.zhihu.com/p/491684586
-XX:+UseCompressedClassPointers:类指针压缩(因为对于任何一个jvm中的对象而言,其内部都有一个指向自己对应类(属于哪个class)的指针(Java习惯叫引用),在64位的Java虚拟机中,默认是启动压缩的,有利于节约内存占用);
-XX:+UseCompressedOops:普通对象指针压缩(表示是否使用普通对象指针压缩,Oops是Ordinary object pointers的缩写,就是任何指向一个在堆中的对象(非简单类型)的指针,默认也是启动压缩的);
-XX:-UseLargePagesIndividualAllocation:与oops一起使用,有关博客表明在较大的页内存使用时,也会自动启动;
-XX:+UseParallelGC:垃圾收集器
参数形式:-XX:+/-参数 # +表示开启,-表示关闭
2、通过pid查看程序的JVM运行参数:jinfo -flags pid值
C:\Users\namejr>tasklist 映像名称 PID 会话名 会话# 内存使用 ========================= ======== ================ =========== ============ java.exe 6288 Console 1 549,544 K tasklist.exe 4312 Console 1 8,628 K
C:\Users\namejr>jinfo -flags 6288 Attaching to process ID 6288, please wait... Debugger attached successfully. Server compiler detected. JVM version is 25.201-b09 Non-default VM flags: -XX:CICompilerCount=3 -XX:InitialHeapSize=268435456 -XX:MaxHeapSize=4265607168 -XX:MaxNewSize=1421869056 -XX:MinHeapDeltaBytes=524288 -XX:NewSize=89128960 -XX:OldSize=179306496 -XX:+UseCompressedClassPointers -XX:+UseCompressedOops -XX:+UseFastUnorderedTimeStamps -XX:-UseLargePagesIndividualAllocation -XX:+UseParallelGC Command line: -Djava.util.logging.config.file=E:\Tomcat\apache-tomcat-8.5.81\conf\logging.properties -Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager -Dfile.encoding=UTF-8 -Djdk.tls.ephemeralDHKeySize=2048 -Djava.protocol.handler.pkgs=org.apache.catalina.webresources -Dignore.endorsed.dirs= -Dcatalina.base=E:\Tomcat\apache-tomcat-8.5.81 -Dcatalina.home=E:\Tomcat\apache-tomcat-8.5.81 -Djava.io.tmpdir=E:\Tomcat\apache-tomcat-8.5.81\temp
-XX:CICompilerCount:最大的并行编译数; -XX:MaxNewSize:新生代堆内存最大值; -XX:MinHeapDeltaBytes:最小扩容内存值(新生代内存满的时候,会进行扩容,如果扩容内存还不够,将会进行GC回收);
-XX:NewSize=新生代的初始内存大小;-XX:OldSize=老年代的初始大小;
-XX:+UseCompressedClassPointers -XX:+UseCompressedOops -XX:+UseFastUnorderedTimeStamps -XX:-UseLargePagesIndividualAllocation -XX:+UseParallelGC(同上)
Command line:
-Djava.util.logging.config.file=E:\Tomcat\apache-tomcat-8.5.81\conf\logging.properties -- 指定日志配置文件
-Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager -- 指定全局日志管理器负责维护日志配置和日志继承结构
-Dfile.encoding=UTF-8 -- 设置编码格式
-Djdk.tls.ephemeralDHKeySize=2048
-Djava.protocol.handler.pkgs=org.apache.catalina.webresources
-Dignore.endorsed.dirs= -Dcatalina.base=E:\Tomcat\apache-tomcat-8.5.81
-Dcatalina.home=E:\Tomcat\apache-tomcat-8.5.81
-Djava.io.tmpdir=E:\Tomcat\apache-tomcat-8.5.81\temp
二、关于程序因长期维持连接占用内存过高
C:\Users\namejr>netstat -ano -- 可查看当前端口占用情况
# 查看指定端口:netstat -ano | findstr :80 活动连接 协议 本地地址 外部地址 状态 PID TCP 0.0.0.0:135 0.0.0.0:0 LISTENING 824 TCP 0.0.0.0:445 0.0.0.0:0 LISTENING 4 TCP 0.0.0.0:3306 0.0.0.0:0 LISTENING 4924 TCP 0.0.0.0:5040 0.0.0.0:0 LISTENING 6872 TCP 0.0.0.0:33060 0.0.0.0:0 LISTENING 4924 TCP 0.0.0.0:49664 0.0.0.0:0 LISTENING 840 TCP 0.0.0.0:49665 0.0.0.0:0 LISTENING 680 TCP 0.0.0.0:49666 0.0.0.0:0 LISTENING 1648 TCP 0.0.0.0:49667 0.0.0.0:0 LISTENING 2644 TCP 0.0.0.0:49668 0.0.0.0:0 LISTENING 2844 TCP 0.0.0.0:49673 0.0.0.0:0 LISTENING 3804 TCP 0.0.0.0:49677 0.0.0.0:0 LISTENING 752 TCP 127.0.0.1:5438 127.0.0.1:56704 ESTABLISHED 5344 TCP 127.0.0.1:8440 0.0.0.0:0 LISTENING 11804 TCP 127.0.0.1:8890 0.0.0.0:0 LISTENING 3924 TCP 127.0.0.1:8990 0.0.0.0:0 LISTENING 3924 TCP 127.0.0.1:9310 0.0.0.0:0 LISTENING 8228 TCP 127.0.0.1:9310 127.0.0.1:15971 ESTABLISHED 8228 TCP 127.0.0.1:10086 0.0.0.0:0 LISTENING 9476 TCP 127.0.0.1:15962 127.0.0.1:15963 ESTABLISHED 8228
C:\Users\namejr>jps -l -- 查看指定进程信息 11604 StartApplication 8228 9124 org.jetbrains.jps.cmdline.Launcher 7992 sun.tools.jps.Jps C:\Users\namejr>netstat -aon|findstr 11604 -- 查看端口占用情况 TCP 127.0.0.1:15963 127.0.0.1:15962 ESTABLISHED 11604 TCP 192.168.129.131:16947 60.190.136.238:30234 CLOSE_WAIT 11604 TCP 192.168.129.131:16949 60.190.136.238:30234 CLOSE_WAIT 11604 TCP 192.168.129.131:16950 60.190.136.238:30234 CLOSE_WAIT 11604 TCP 192.168.129.131:16952 60.190.136.238:30234 CLOSE_WAIT 11604 TCP 192.168.129.131:16953 60.190.136.238:30234 CLOSE_WAIT 11604 TCP 192.168.129.131:16954 60.190.136.238:30234 CLOSE_WAIT 11604 TCP 192.168.129.131:16956 60.190.136.238:30234 CLOSE_WAIT 11604 TCP 192.168.129.131:16958 60.190.136.238:30234 CLOSE_WAIT 11604 TCP 192.168.129.131:16959 60.190.136.238:30234 CLOSE_WAIT 11604 TCP 192.168.129.131:16960 60.190.136.238:30234 CLOSE_WAIT 11604 TCP 192.168.129.131:16961 60.190.136.238:30234 CLOSE_WAIT 11604 TCP 192.168.129.131:16962 60.190.136.238:30234 CLOSE_WAIT 11604 TCP 192.168.129.131:16963 60.190.136.238:30234 CLOSE_WAIT 11604 TCP 192.168.129.131:16964 60.190.136.238:30234 CLOSE_WAIT 11604 TCP 192.168.129.131:16965 60.190.136.238:30234 CLOSE_WAIT 11604 TCP 192.168.129.131:16966 60.190.136.238:30234 CLOSE_WAIT 11604 TCP 192.168.129.131:16967 60.190.136.238:30234 CLOSE_WAIT 11604 TCP 192.168.129.131:16968 60.190.136.238:30234 CLOSE_WAIT 11604 TCP 192.168.129.131:16969 60.190.136.238:30234 CLOSE_WAIT 11604 TCP 192.168.129.131:16970 60.190.136.238:30234 CLOSE_WAIT 11604 TCP 192.168.129.131:16971 60.190.136.238:30234 CLOSE_WAIT 11604
汇总:
jps 查看所有的jvm进程,包括进程ID,进程启动的路径等等。
-q:只输出LVMID,省略主类的名称;
-m:输出虚拟机进程启动时传递给主类mainO函数的参数;
-l:输出主类的全名,如果进程执行的是JAR包,则输出JAR路径;
-v:输出虚拟机进程启动时的JVM参数。
C:\Users\namejr>jps -l # 查看运行的进程id 2464 -- process information unavailable 4160 com.namejr.StartApplication 7572 org.jetbrains.jps.cmdline.Launcher 6760 org.jetbrains.idea.maven.server.RemoteMavenServer36 8200 11004 sun.tools.jps.Jps
C:\Users\namejr>jps -v # 查看进程启动时的JVM参数(建议还是使用"jinfo -flags pid"会更加详细)
12644 Jps -Dapplication.home=C:\Program Files\Java\jdk1.8.0_201 -Xms8m
3700 RemoteMavenServer36 -Djava.awt.headless=true -Dmaven.defaultProjectBuilder.disableGlobalModelCache=true -Didea.version=2023.2.2 -Didea.maven.embedder.version=3.8.6 -Xmx768m -Dmaven.ext.class.path=C:\Users\namejr\idea\IntelliJ IDEA 2023.2.2\plugins\maven\lib\maven-event-listener.jar -Dfile.encoding=UTF-8
12940 exit -XX:ErrorFile=C:\Users\namejr\\java_error_in_idea64_%p.log -XX:HeapDumpPath=C:\Users\namejr\\java_error_in_idea64.hprof -Xms128m -Xmx2048m -XX:ReservedCodeCacheSize=512m -XX:+IgnoreUnrecognizedVMOptions -XX:+UseG1GC -XX:SoftRefLRUPolicyMSPerMB=50 -XX:CICompilerCount=2 -XX:+HeapDumpOnOutOfMemoryError -XX:-OmitStackTraceInFastThrow -ea -Dsun.io.useCanonCaches=false -Djdk.http.auth.tunneling.disabledSchemes="" -Djdk.attach.allowAttachSelf=true -Djdk.module.illegalAccess.silent=true -Dkotlinx.coroutines.debug=off -XX:ErrorFile=$USER_HOME/java_error_in_idea_%p.log -XX:HeapDumpPath=$USER_HOME/java_error_in_idea.hprof --add-opens=java.base/jdk.internal.org.objectweb.asm=ALL-UNNAMED --add-opens=java.base/jdk.internal.org.objectweb.asm.tree=ALL-UNNAMED -Dfile.encoding=UTF-8 -javaagent:C:\Users\namejr\idea\jetbra\ja-netfilter.jar=jetbrains -Djb.vmOptionsFile=C:\Users\namejr\idea\jetbra\vmoptions\idea.vmoptions -Djava.system.class.loader=com.intellij.util.lang.PathClassLoader -Didea.vendor.name=JetBrains -Didea.pat
jstack
jstack(Java Stack Trace,Java堆栈跟踪工具),这个命令用于查看虚拟机当前时刻的线程快照(一般是thread dump 或者 java core文件)。线程快照就是当前虚拟机内每一条线程正在执行的方法堆栈的集合。生成线程快照的主要目的是定位线程出现长时间停顿的原因,入线程间死锁、死循环、请求外部资源导致的长时间等待都是导致线程长时间停顿的常见原因。线程出现停顿的时候通过jstack来查看各个线程的调用堆栈,就可以知道没有响应的线程到底在后台做些什么事情。
C:\Users\namejr>jstack 4160 2024-03-20 14:42:39 Full thread dump Java HotSpot(TM) 64-Bit Server VM (25.201-b09 mixed mode): "DestroyJavaVM" #44 prio=5 os_prio=0 tid=0x000000002096f800 nid=0x29f8 waiting on condition [0x0000000000000000] java.lang.Thread.State: RUNNABLE "http-nio-8080-Acceptor" #43 daemon prio=5 os_prio=0 tid=0x000000002096f000 nid=0x2520 runnable [0x0000000022dae000] java.lang.Thread.State: RUNNABLE at sun.nio.ch.ServerSocketChannelImpl.accept0(Native Method) at sun.nio.ch.ServerSocketChannelImpl.accept(ServerSocketChannelImpl.java:422) at sun.nio.ch.ServerSocketChannelImpl.accept(ServerSocketChannelImpl.java:250) - locked <0x000000076d0bdd88> (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(Thread.java:748) "http-nio-8080-Poller" #42 daemon prio=5 os_prio=0 tid=0x0000000020971000 nid=0x37d4 runnable [0x0000000022cae000] java.lang.Thread.State: RUNNABLE at sun.nio.ch.WindowsSelectorImpl$SubSelector.poll0(Native Method) at sun.nio.ch.WindowsSelectorImpl$SubSelector.poll(WindowsSelectorImpl.java:296) at sun.nio.ch.WindowsSelectorImpl$SubSelector.access$400(WindowsSelectorImpl.java:278) at sun.nio.ch.WindowsSelectorImpl.doSelect(WindowsSelectorImpl.java:159) at sun.nio.ch.SelectorImpl.lockAndDoSelect(SelectorImpl.java:86) - locked <0x000000076d2c4268> (a sun.nio.ch.Util$3) - locked <0x000000076d2c31c0> (a java.util.Collections$UnmodifiableSet) - locked <0x000000076d2c3008> (a sun.nio.ch.WindowsSelectorImpl) at sun.nio.ch.SelectorImpl.select(SelectorImpl.java:97) at org.apache.tomcat.util.net.NioEndpoint$Poller.run(NioEndpoint.java:805) at java.lang.Thread.run(Thread.java:748)
.......................................................
........................................................
java.lang.Thread.State: RUNNABLE "Signal Dispatcher" #4 daemon prio=9 os_prio=2 tid=0x000000001cb96800 nid=0x2c48 runnable [0x0000000000000000] java.lang.Thread.State: RUNNABLE "Finalizer" #3 daemon prio=8 os_prio=1 tid=0x00000000035a9800 nid=0x1528 in Object.wait() [0x000000001dede000] java.lang.Thread.State: WAITING (on object monitor) at java.lang.Object.wait(Native Method) - waiting on <0x00000006c1c19390> (a java.lang.ref.ReferenceQueue$Lock) at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:144) - locked <0x00000006c1c19390> (a java.lang.ref.ReferenceQueue$Lock) at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:165) at java.lang.ref.Finalizer$FinalizerThread.run(Finalizer.java:216) "Reference Handler" #2 daemon prio=10 os_prio=2 tid=0x00000000035a6000 nid=0x3338 in Object.wait() [0x000000001ddde000] java.lang.Thread.State: WAITING (on object monitor) at java.lang.Object.wait(Native Method) - waiting on <0x00000006c1c193d0> (a java.lang.ref.Reference$Lock) at java.lang.Object.wait(Object.java:502) at java.lang.ref.Reference.tryHandlePending(Reference.java:191) - locked <0x00000006c1c193d0> (a java.lang.ref.Reference$Lock) at java.lang.ref.Reference$ReferenceHandler.run(Reference.java:153) "VM Thread" os_prio=2 tid=0x000000001cb47800 nid=0x2de4 runnable "GC task thread#0 (ParallelGC)" os_prio=0 tid=0x00000000034cb800 nid=0x2ff8 runnable "GC task thread#1 (ParallelGC)" os_prio=0 tid=0x00000000034cd000 nid=0x37cc runnable "GC task thread#2 (ParallelGC)" os_prio=0 tid=0x00000000034ce800 nid=0x3140 runnable "GC task thread#3 (ParallelGC)" os_prio=0 tid=0x00000000034d1000 nid=0x1bcc runnable "VM Periodic Task Thread" os_prio=2 tid=0x000000001ee15000 nid=0x1d28 waiting on condition JNI global references: 18153
jstat
jstat(JVM Statistics Monitoring Tool,虚拟机统计信息监视工具),这个命令用于监视虚拟机各种运行状态信息。它可以显示本地或者远程虚拟机进程中的类装载、内存、垃圾收集、JIT编译等运行数据,虽然没有GUI图形界面,只是提供了纯文本控制台环境的服务器上,但它是运行期间定位虚拟机性能问题的首选工具。
假设需要每250毫秒查询一次进程2764(如果是本地虚拟机进程,VMID与LVMID是一致的;如果是远程虚拟机进程,VMID的格式)垃圾收集状况,一共查询20次,那命令应当是:jstat -gc 2764 250 20
C:\Users\namejr>jstat -gc 4160 # 显示使用情况 S0C S1C S0U S1U EC EU OC OU MC MU CCSC CCSU YGC YGCT FGC FGCT GCT 10752.0 10752.0 8050.9 0.0 131072.0 44244.4 73216.0 6151.4 28208.0 26316.6 3888.0 3445.8 4 0.023 1 0.030 0.052 C:\Users\namejr>jstat -gcutil 4160 # 显示使用百分比情况
S0 S1 E O M CCS YGC YGCT FGC FGCT GCT
74.88 0.00 33.76 8.40 93.29 88.63 4 0.023 1 0.030 0.052
区域 | 含义 |
S0C | Survivor0 第一个幸存区的容量大小 |
S1C | Survivor1 第二个幸存区的容量大小 |
S0U | Survivor0 第一个幸存区已使用的内存大小 |
S1U | Survivor1 第二个幸存区已使用的内存大小 |
EC | Eden 新生代的容量大小 |
EU | Eden 新生代已使用的内存大小 |
OC | Old 老年代的容量大小 |
OU | Old 老年代已使用的内存大小 |
MC | Meta 方法区的容量大小 |
MU | Meta 方法区已使用的内存大小 |
YGC | Young GC发生的次数 |
YGCT | Young GC的总耗时 |
FGC | Full GC发生的次数 |
FGCT | Full GC的总耗时 |
jmap
jmap(Memory Map for Java,内存映像工具),用于生成堆转存的快照,一般是heapdump或者dump文件。如果不适用jmap命令,可以使用-XX:+HeapDumpOnOutOfMemoryError参数,当虚拟机发生内存溢出的时候可以产生快照。或者使用kill -3 pid也可以产生。jmap的作用并不仅仅是为了获取dump文件,它可以查询finalize执行队列,java堆和永久代的详细信息,如空间使用率,当前用的哪种收集器。
C:\Users\namejr>jmap -histo 4160 num #instances #bytes class name ---------------------------------------------- 1: 42007 18560760 [B 2: 10580 14511248 [I 3: 113154 12944072 [C 4: 74489 1787736 java.lang.String 5: 10785 949080 java.lang.reflect.Method 6: 13789 762624 [Ljava.lang.Object; 7: 35346 735032 [Ljava.lang.Class; 8: 6327 701928 java.lang.Class 9: 13713 438816 java.util.concurrent.ConcurrentHashMap$Node 10: 4672 407304 [Ljava.util.HashMap$Node; 11: 8856 354240 java.util.LinkedHashMap$Entry ........................................................................... ........................................................................... 3112: 1 16 sun.util.calendar.Gregorian 3113: 1 16 sun.util.locale.provider.AuxLocaleProviderAdapter$NullProvider 3114: 1 16 sun.util.locale.provider.CalendarDataUtility$CalendarWeekParameterGetter 3115: 1 16 sun.util.locale.provider.SPILocaleProviderAdapter 3116: 1 16 sun.util.locale.provider.TimeZoneNameUtility$TimeZoneNameGetter 3117: 1 16 sun.util.resources.LocaleData 3118: 1 16 sun.util.resources.LocaleData$LocaleDataResourceBundleControl Total 551590 59849472
jinfo
jinfo (Configuration Info for Java,配置信息工具) 这个命令可以实时地查看和调整虚拟机各项参数。
C:\Users\namejr>jinfo -flags 4160 # 查看进程信息 Attaching to process ID 4160, please wait... Debugger attached successfully. Server compiler detected. JVM version is 25.201-b09 Non-default VM flags: -XX:-BytecodeVerificationLocal -XX:-BytecodeVerificationRemote -XX:CICompilerCount=3 -XX:InitialHeapSize=268435456 -XX:+ManagementServer -XX:MaxHeapSize=4265607168 -XX:MaxNewSize=1421869056 -XX:MinHeapDeltaBytes=524288 -XX:NewSize=89128960 -XX:OldSize=179306496 -XX:TieredStopAtLevel=1 -XX:+UseCompressedClassPointers -XX:+UseCompressedOops -XX:+UseFastUnorderedTimeStamps -XX:-UseLargePagesIndividualAllocation -XX:+UseParallelGC Command line: -agentlib:jdwp=transport=dt_socket,address=127.0.0.1:6282,suspend=y,server=n -XX:TieredStopAtLevel=1 -Xverify:none -Dspring.output.ansi.enabled=always -Dcom.sun.management.jmxremote -Dspring.jmx.enabled=true -Dspring.liveBeansView.mbeanDomain -Dspring.application.admin.enabled=true -Dmanagement.endpoints.jmx.exposure.include=* -javaagent:C:\Users\namejr\AppData\Local\JetBrains\IntelliJIdea2023.2\captureAgent\debugger-agent.jar -Dfile.encoding=UTF-8
C:\Users\namejr>jinfo -sysprops 4160 # 查看系统属性
jconsole
一个java GUI监视工具,可以以图表化的形式显示各种数据。并可通过远程连接监视远程的服务器VM。用java写的GUI程序,用来监控VM,并可监控远程的VM,非常易用,而且功能非常强。命令行里打 jconsole,选则进程就可以了。
使用步骤
jvisualvm
同jconsole都是一个基于图形化界面的、可以查看本地及远程的JAVA GUI监控工具,Jvisualvm同jconsole的使用方式一样,直接在命令行打入jvisualvm即可启动,jvisualvm界面更美观一些,数据更实时。
调优相关:
相关配置处理:
# 最大工作线程数。Spring boot自带的tomcat线程数默认值为200个 server.tomcat.max-threads=50 # 服务器在任何给定时间接受和处理的最大连接数。 server.tomcat.max-connections=0 # HTTP消息头的最大大小(以字节为单位)。 server.tomcat.max-http-header-size=0 # HTTP post内容的最大大小(以字节为单位)。 server.tomcat.max-http-form-post-size=0 # 最小工作线程数。 server.tomcat.min-spare-threads=0
JVM内存模型结构:具体可查看(以下仅作笔记使用)【Java面试题汇总】JVM篇(2023版)_jvm面试题2023-CSDN博客
关于常量池个数问题:jvm 在执行某个类的时候,必须经过加载、连接、初始化,而连接又包括验证、准备、解析三个阶段。而当类加载到内存中后,jvm 就会将class常量池中的内容存放到运行时常量池中,由此可知,运行时常量池也是每个类都有一个。详情请查看:【JVM】Java 中的三种常量池_jvm 运行时常量池有几个-CSDN博客