当前位置: 首页 > news >正文

遵义市住房和城乡建设局网站wordpress 列表封面

遵义市住房和城乡建设局网站,wordpress 列表封面,如何对产品进行推广,自媒体可做外链网站性能问题是软件工程师在日常工作中需要经常面对和解决的问题,在用户体验至上的今天,解决好应用的性能问题能带来非常大的收益。 工欲善其事,必先利其器,想要解决性能相关问题,必须要有比较好的性能诊断工具。Java作为最…

性能问题是软件工程师在日常工作中需要经常面对和解决的问题,在用户体验至上的今天,解决好应用的性能问题能带来非常大的收益。

工欲善其事,必先利其器,想要解决性能相关问题,必须要有比较好的性能诊断工具。Java作为最流行的编程语言之一,应用的性能诊断一直受到业界广泛关注。

造成Java应用出现性能问题的因素非常多,例如线程控制、磁盘读写、数据库访问、网络I/O、垃圾收集等。

想要定位这些问题,一款优秀的性能诊断工具必不可少,就好比中医、西医看病,中医讲究的是望、闻、问、切,西医则是借助各种检查仪器。

(一)概述

JDK本身已经集成了很多诊断工具。在大家刚接触Java学习的时候,最先了解的两个命令就是javac和java,但是除此之外,还有一些其他工具可以使用,可是并非所有的程序员都了解其他命令行程序的作用,接下来我们一起看看其他命令行程序的作用。

进入到安装JDK的bin目录,会发现还有一系列辅助工具。这些辅助工具用来获取目标JVM不同方面、不同层次的信息,帮助开发人员很好地解决Java应用程序的一些疑难杂症。

Windows系统bin目录的内容如图所示:
在这里插入图片描述
虽然在Windows系统下都是exe格式的可执行文件。

但事实上,它们只是Java程序的一层包装,其真正实现是在tools.jar中,如图所示。
在这里插入图片描述

以jps工具为例,在控制台执行jps命令和执行java -classpath %Java_HOME%/lib/tools.jar sun.tools.jps.Jps命令是等价的,即jps.exe只是这个命令的一层包装。下面介绍一些常用的命令工具。

(二)jps:查看正在运行的Java进程

jps(JVM Process Status Tool)命令用于查看系统内所有的JVM进程,可根据参数选项指定是否显示JVM的执行主类[包含main()方法的类],以及进程的本地JVMID(Local Virtual Machine Identifier),对于本地JVM进程来说,进程的本地JVMID与操作系统的进程ID是一致的。

简单来说,就是Java提供的一个显示当前所有Java进程pid的命令,和Linux系统里的ps命令很相似,ps命令主要是用来显示当前系统的进程情况,比如查看进程列表和进程ID。

在日常工作中,此命令也是最常用的命令之一。

jps的基本使用语法如下。

jps  [ options ] [ hostid ]

1. [ options ]选项说明

jps工具[options]主要选项如表所示。

在这里插入图片描述

2. [hostid]说明

hostid表示目标主机的主机名或IP地址,如果省略该参数,则目标主机为本地主机。如果想要远程监控主机上的Java程序,需要安装jstatd​。

对于网络安全要求非常严格的场所,需要自定义策略文件来满足对特定的主机或网络的访问,但是这种技术容易受到IP地址欺诈攻击。

如果由于安全问题无法通过定制的策略文件处理,那么最安全的操作是在主机本地使用jstatjps工具。

3.使用案例

一般来说,java开发的war包或jar包都依赖tomcat来运行。

在Linux上启动Tomcat​,然后在Linux上面使用ps命令查看Tomcat进程ID使用,如下所示:

ps -ef | grep  "tomcat"

在这里插入图片描述
可以查看到Tomcat进程ID也是3460,与ps命令一致。

jps
(1)-q选项:只输出进程ID,省略主类名称。
jps -q

这个方法可以用于写shell脚本时,关闭指定的java进程。
在这里插入图片描述

(2)-m选项:输出JVM进程启动时传递给主类main()方法的参数。
jps -m

这个方法可以查看JVM启动时指定的运行端口。

在这里插入图片描述

(3)-v选项:查看输出JVM进程启动时的JVM参数。
jps -v

这个经常命令用于查看JVM启动配置。

在这里插入图片描述

(二)jstat:查看JVM统计信息

jstat(JVM Statistics Monitoring Tool)用于收集JVM各方面的运行数据,显示本地或远程JVM进程中的类装载、内存、垃圾收集、JIT编译等运行数据。

在没有图形用户界面时,只提供了纯文本控制台环境的服务器上,它是运行期定位JVM性能问题的首选工具。

常用于检测垃圾回收问题以及内存泄漏问题。它的功能非常强大,可以通过它查看堆信息的详细情况。

jstat的基本使用语法如下:

jstat -<option>[-t] [-h<lines>] <vmid>[<interval>[<count>]]

使用下面的命令可以查看jstat相关参数。

jstat -h 或 jstat -help

1.[options]选项说明

jstat工具[options]主要选项如表所示。

选项作用
-class监视类装载、卸载数量、总空间以及类装载所耗费的时间
-gc监视Java堆状况,包括Eden区、两个survivor区、老年代、方法区等的容量、已用空间、GC时间合计等信息
-gccapacity监视内容与-gc基本相同,但输出主要关注Java堆各个区域使用到的最大、最小空间
-gcutil监视内容与-gc基本相同,但输出主要关注已使用空间占总空间的百分比
-gccauses与-gcutil功能一样,但是会额外输出导致上一次GC产生的原因
-gcnew监视新生代GC状况
-gcnewcapacity监视内容与-gcnew基本相同,输出主要关注使用到的最大、最小空间
-gcold监视老年代GC状况
-gcoldcapacity监视内容与-gcold基本相同,输出主要关注使用到的最大、最小空间
-gcpermcapacity输出永久代使用到的最大、最小空间(JDK8之前的版本)
-compiler输出JIT编译器编译过的方法、耗时等信息
-printcompilation输出已经被JIT编译的方法

2.[-t]参数说明

[-t]参数可以在输出信息前加上一个Timestamp列,显示程序的运行时间。可以比较Java进程的启动时间以及总GC时间(GCT列)​,或者两次测量的间隔时间以及总GC时间的增量,来得出GC时间占运行时间的比例。

如果该比例超过20%,则说明目前堆的压力较大;如果该比例超过90%,则说明堆里几乎没有可用空间,随时都可能抛出OOM异常。

3.[-h<lines>]参数说明

[-h]参数可以在周期性数据输岀时,输出设定的行数的数据后输出一个表头信息。

4.[interval]参数说明

[interval]参数用于指定输出统计数据的周期,单位为毫秒,简单来说就是查询间隔时间。

5.[count]参数说明

[count]用于指定查询的总次数。

6.使用案例

由于jstat参数选项比较多,这里只列举一个启动了Tomcat的Linux服务器案例,查看其监视状态,命令如下所示。

# 查看进程ID
jps# 查看进程GC信息
jstat -gc 3460# 每隔1s打印一次进程信息 打印10次 并且加上时间戳
jstat -gc -t 3460 1000 10# 每隔1s打印一次进程信息 打印10次 并且加上时间戳 且每5行输出一次表头信息
jstat -gc -t -h5 3460 1000 10

在这里插入图片描述
运行结果的各列表示的含义如表所示。

参数含义
S0C新生代中第一个 survivor(幸存区)的容量(字节)
S1C新生代中第二个 survivor(幸存区)的容量(字节)
S0U新生代中第一个 survivor(幸存区)目前已使用空间(字节)
S1U新生代中第二个 survivor(幸存区)目前已使用空间(字节)
EC新生代中 Eden(伊甸园)的容量(字节)
EU新生代中 Eden(伊甸园)目前已使用空间(字节)
OC老年代的容量(字节)
OU老年代目前已使用空间(字节)
MCMetaSpace 区的容量
MUMetaSpace 区目前已经使用的空间
CCSC压缩类空间总容量
CCSU压缩类空间已经使用的空间
YGC从应用程序启动到采样时 YoungGC 的次数
YGCT从应用程序启动到采样时 YoungGC 消耗的时间(秒)
FGC从应用程序启动到采样时 Full GC 的次数
FGCT从应用程序启动到采样时 Full GC 的消耗的时间(秒)
GCT从应用程序启动到采样时 GC 用的总时间(秒)

jstat还可以用来判断是否出现内存泄漏,步骤如下。

  • (1)在长时间运行的Java程序中,可以运行jstat命令连续获取多行性能数据,并取这几行数据中OU列(即已占用的老年代内存)的最小值。
  • (2)每隔一段较长的时间重复一次上述操作,获得多组OU最小值。如果这些值呈上涨趋势,则说明该Java程序的老年代内存已使用量在不断上涨,这意味着无法回收的对象在不断增加,因此很有可能存在内存泄漏。

一个内存泄漏的例子:

public class MemoryLeakExample {private static List<String> cache = new ArrayList<>();public void addToCache() {while (true) {cache.add("Leaking string " + System.nanoTime());try {Thread.sleep(1);} catch (InterruptedException e) {break;}}}
}

该代码的cachestatic 的,永远不会被释放。字符串不断加入,堆内存持续增长,最终抛出 OutOfMemoryError,程序终止。

这会导致刚开始一切正常,几个月后突然 OOM,难以排查。

(三)jinfo:实时查看和修改JVM配置参数

jinfo(Configuration Info for Java)可用于查看和调整JVM的配置参数。

在很多情况下,Java应用程序不会指定所有的JVM参数。

而此时,开发人员可能不知道某一个具体的JVM参数的默认值。

在这种情况下,可能需要通过查找文档获取某个参数的默认值。这个查找过程可能是非常艰难的。但有了jinfo工具,开发人员可以很方便地找到JVM参数的当前值。

上面讲解的jps -v命令虽然可以查看JVM启动时显示指定的参数列表,但是如果想要知道未被显示指定的参数的系统默认值,就需要用到jinfo工具了。

第二个作用就是在程序运行时修改部分参数,并使之立即生效。并非所有参数都支持动态修改,只有被标记为manageable的参数可以被实时修改。

其实,这个修改能力是极其有限的,使用下面的命令查看被标记为manageable的参数。

java -XX:+PrintFlagsFinal -version | grep manageable

在这里插入图片描述
jinfo的基本使用语法如下:

jinfo  [ options ]  pid

1. [ options ]选项说明jinfo工具options主要选项如表所示。

在这里插入图片描述
根据进程ID查询全部参数和系统属性。

# 查看全部参数和系统属性
jinfo 4571

示例结果如下所示

Attaching to process ID 4571, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 25.412-b08
Java System Properties:java.vendor = Red Hat, Inc.
sun.java.launcher = SUN_STANDARD
catalina.base = /usr/local/tomcat
sun.management.compiler = HotSpot 64-Bit Tiered Compilers
catalina.useNaming = true
os.name = Linux
sun.boot.class.path = /usr/lib/jvm/java-1.8.0-openjdk-1.8.0.412.b08-1.el7_9.x86_64/jre/lib/resources.jar:/usr/lib/jvm/java-1.8.0-openjdk-1.8.0.412.b08-1.el7_9.x86_64/jre/lib/rt.jar:/usr/lib/jvm/java-1.8.0-openjdk-1.8.0.412.b08-1.el7_9.x86_64/jre/lib/sunrsasign.jar:/usr/lib/jvm/java-1.8.0-openjdk-1.8.0.412.b08-1.el7_9.x86_64/jre/lib/jsse.jar:/usr/lib/jvm/java-1.8.0-openjdk-1.8.0.412.b08-1.el7_9.x86_64/jre/lib/jce.jar:/usr/lib/jvm/java-1.8.0-openjdk-1.8.0.412.b08-1.el7_9.x86_64/jre/lib/charsets.jar:/usr/lib/jvm/java-1.8.0-openjdk-1.8.0.412.b08-1.el7_9.x86_64/jre/lib/jfr.jar:/usr/lib/jvm/java-1.8.0-openjdk-1.8.0.412.b08-1.el7_9.x86_64/jre/classes
java.util.logging.config.file = /usr/local/tomcat/conf/logging.properties
org.apache.el.GET_CLASSLOADER_USE_PRIVILEGED = false
java.vm.specification.vendor = Oracle Corporation
java.runtime.version = 1.8.0_412-b08
user.name = www
tomcat.util.scan.StandardJarScanFilter.jarsToScan = log4j-taglib*.jar,log4j-web*.jar,log4javascript*.jar,slf4j-taglib*.jar
shared.loader = 
tomcat.util.buf.StringCache.byte.enabled = true
user.language = en
java.naming.factory.initial = org.apache.naming.java.javaURLContextFactory
sun.boot.library.path = /usr/lib/jvm/java-1.8.0-openjdk-1.8.0.412.b08-1.el7_9.x86_64/jre/lib/amd64
jdk.tls.ephemeralDHKeySize = 2048
java.version = 1.8.0_412
java.util.logging.manager = org.apache.juli.ClassLoaderLogManager
user.timezone = Asia/Shanghai
sun.arch.data.model = 64
java.util.concurrent.ForkJoinPool.common.threadFactory = org.apache.catalina.startup.SafeForkJoinWorkerThreadFactory
java.endorsed.dirs = /usr/lib/jvm/java-1.8.0-openjdk-1.8.0.412.b08-1.el7_9.x86_64/jre/lib/endorsed
sun.cpu.isalist = 
sun.jnu.encoding = UTF-8
file.encoding.pkg = sun.io
package.access = sun.,org.apache.catalina.,org.apache.coyote.,org.apache.jasper.,org.apache.tomcat.
file.separator = /
java.specification.name = Java Platform API Specification
java.class.version = 52.0
user.country = US
java.home = /usr/lib/jvm/java-1.8.0-openjdk-1.8.0.412.b08-1.el7_9.x86_64/jre
java.vm.info = mixed mode
os.version = 3.10.0-957.el7.x86_64
path.separator = :
java.vm.version = 25.412-b08
java.protocol.handler.pkgs = org.apache.catalina.webresources
java.awt.printerjob = sun.print.PSPrinterJob
sun.io.unicode.encoding = UnicodeLittle
java.specification.maintenance.version = 5
awt.toolkit = sun.awt.X11.XToolkit
package.definition = sun.,java.,org.apache.catalina.,org.apache.coyote.,org.apache.jasper.,org.apache.naming.,org.apache.tomcat.
java.naming.factory.url.pkgs = org.apache.naming
java.security.egd = file:/dev/./urandom
user.home = /home/www
org.apache.catalina.security.SecurityListener.UMASK = 0027
java.specification.vendor = Oracle Corporation
tomcat.util.scan.StandardJarScanFilter.jarsToSkip = annotations-api.jar,ant-junit*.jar,ant-launcher*.jar,ant*.jar,asm-*.jar,aspectj*.jar,bcel*.jar,biz.aQute.bnd*.jar,bootstrap.jar,catalina-ant.jar,catalina-ha.jar,catalina-ssi.jar,catalina-storeconfig.jar,catalina-tribes.jar,catalina.jar,cglib-*.jar,cobertura-*.jar,commons-beanutils*.jar,commons-codec*.jar,commons-collections*.jar,commons-compress*.jar,commons-daemon.jar,commons-dbcp*.jar,commons-digester*.jar,commons-fileupload*.jar,commons-httpclient*.jar,commons-io*.jar,commons-lang*.jar,commons-logging*.jar,commons-math*.jar,commons-pool*.jar,derby-*.jar,dom4j-*.jar,easymock-*.jar,ecj-*.jar,el-api.jar,geronimo-spec-jaxrpc*.jar,h2*.jar,ha-api-*.jar,hamcrest-*.jar,hibernate*.jar,httpclient*.jar,icu4j-*.jar,jasper-el.jar,jasper.jar,jaspic-api.jar,jaxb-*.jar,jaxen-*.jar,jaxws-rt-*.jar,jdom-*.jar,jetty-*.jar,jmx-tools.jar,jmx.jar,jsp-api.jar,jstl.jar,jta*.jar,junit-*.jar,junit.jar,log4j*.jar,mail*.jar,objenesis-*.jar,oraclepki.jar,org.hamcrest.core_*.jar,org.junit_*.jar,oro-*.jar,servlet-api-*.jar,servlet-api.jar,slf4j*.jar,taglibs-standard-spec-*.jar,tagsoup-*.jar,tomcat-api.jar,tomcat-coyote.jar,tomcat-dbcp.jar,tomcat-i18n-*.jar,tomcat-jdbc.jar,tomcat-jni.jar,tomcat-juli-adapters.jar,tomcat-juli.jar,tomcat-util-scan.jar,tomcat-util.jar,tomcat-websocket.jar,tools.jar,unboundid-ldapsdk-*.jar,websocket-api.jar,wsdl4j*.jar,xercesImpl.jar,xml-apis.jar,xmlParserAPIs-*.jar,xmlParserAPIs.jar,xom-*.jar
java.library.path = /usr/local/apr/lib
java.vendor.url = https://www.redhat.com/
java.vm.vendor = Red Hat, Inc.
common.loader = "${catalina.base}/lib","${catalina.base}/lib/*.jar","${catalina.home}/lib","${catalina.home}/lib/*.jar"
java.runtime.name = OpenJDK Runtime Environment
sun.java.command = org.apache.catalina.startup.Bootstrap start
java.class.path = /usr/local/tomcat/bin/bootstrap.jar:/usr/local/tomcat/bin/tomcat-juli.jar
java.vm.specification.name = Java Virtual Machine Specification
java.vm.specification.version = 1.8
catalina.home = /usr/local/tomcat
sun.cpu.endian = little
sun.os.patch.level = unknown
java.io.tmpdir = /usr/local/tomcat/temp
java.vendor.url.bug = https://access.redhat.com/support/cases/
server.loader = 
os.arch = amd64
java.awt.graphicsenv = sun.awt.X11GraphicsEnvironment
java.ext.dirs = /usr/lib/jvm/java-1.8.0-openjdk-1.8.0.412.b08-1.el7_9.x86_64/jre/lib/ext:/usr/java/packages/lib/ext
user.dir = /
line.separator = java.vm.name = OpenJDK 64-Bit Server VM
ignore.endorsed.dirs = 
file.encoding = UTF-8
java.specification.version = 1.8VM Flags:
Non-default VM flags: -XX:CICompilerCount=12 -XX:InitialHeapSize=268435456 -XX:MaxHeapSize=8327790592 -XX:MaxNewSize=2775580672 -XX:MinHeapDeltaBytes=524288 -XX:NewSize=89128960 -XX:OldSize=179306496 -XX:+UseCompressedClassPointers -XX:+UseCompressedOops -XX:+UseParallelGC 
Command line:  -Djava.util.logging.config.file=/usr/local/tomcat/conf/logging.properties -Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager -Djava.security.egd=file:/dev/./urandom -Xms256m -Xmx7941m -Dfile.encoding=UTF-8 -Djdk.tls.ephemeralDHKeySize=2048 -Djava.protocol.handler.pkgs=org.apache.catalina.webresources -Dorg.apache.catalina.security.SecurityListener.UMASK=0027 -Djava.library.path=/usr/local/apr/lib -Dignore.endorsed.dirs= -Dcatalina.base=/usr/local/tomcat -Dcatalina.home=/usr/local/tomcat -Djava.io.tmpdir=/usr/local/tomcat/temp

(五)jmap:导出内存映像文件和内存使用情况

jmap(JVM Memory Map)用于生成JVM的内存转储快照,生成heapdump文件且可以查询finalize执行队列,以及Java堆与元空间的一些信息。

jmap的作用并不仅仅是为了获取dump文件(堆转储快照文件,二进制文件)​,它还可以获取目标Java进程的内存相关信息,包括Java堆各区域的使用情况、堆中对象的统计信息、类加载信息等。

开发人员可以在控制台中输入命令“jmap-help”​,查阅jmap工具的具体使用方式和标准选项配置。jmap的基本使用语法如下。

jmap [option] <pid>
jmap [option] <executable <core>
jmap [option] [server_id@]<remote server IP or hostname>

1.[ options ]选项说明

jmap工具[options]主要选项如表所示。

在这里插入图片描述

# 示例 1: 使用 jmap 获取指定进程的堆内存信息
jmap -heap <pid># 示例 2: 使用 jmap 获取指定进程的类统计信息
jmap -histo <pid># 示例 3: 使用 jmap 将指定进程的堆内存转储到文件中
jmap -dump:format=b,file=heapdump.hprof <pid># 示例 4: 使用 jmap 获取远程服务器上指定进程的堆内存信息
jmap -heap [server_id@]<remote server IP or hostname>:<pid># 示例 5: 使用 jmap 分析 core 文件
jmap -histo <executable> <core>

这些参数和Linux下输入显示的命令多少会有一些不同,也受JDK版本的影响。其中选项-dump、-heap、-histo是开发人员在工作中使用频率较高的指令。

2. 使用案例

(1)-dump选项:导出内存映像文件。

一般来说,使用jmap指令生成dump文件的操作算得上是最常用的jmap命令之一,将堆中所有存活对象导出至一个文件之中。

执行该命令,JVM会将整个Java堆二进制格式转储到指定filename的文件中。

live子选项是可选的,如果指定了live子选项,堆中只有存活的对象会被转储。通常在写dump文件前会触发一次Full GC,所以dump文件里保存的都是Full GC后留下的对象信息。

由于生成dump文件比较耗时,因此大家需要耐心等待,尤其是大内存镜像生成dump文件需要耗费更长的时间来完成。

如果想要浏览dump文件,读者可以使用jhat(Java堆分析工具)读取生成的文件,也可以使用可视化工具进行解读,比如MAT内存分析工具。

获取dump文件有手动获取和自动获取两种方式。

手动获取的意思是当发现系统需要优化或者需要解决内存问题时,需要开发者主动执行jmap命令,导出dump文件,手动获取命令如下。

#手动获取堆内存全部信息
jmap -dump:format=b,file=<filename.hprof> <pid>
#手动获取堆内存存活对象全部信息
jmap -dump:live,format=b,file=<filename.hprof> <pid>

代码演示:

import java.util.ArrayList;/*** -Xms60m -Xmx60m -XX:SurvivorRatio=8*/
public class GCTest {public static void main(String[] args) {ArrayList<byte[]> list = new ArrayList<>();for (int i = 0; i < 1000; i++) {byte[] arr = new byte[1024 * 100]; // 100KBlist.add(arr);try {Thread.sleep(60);} catch (InterruptedException e) {e.printStackTrace();}}}
}
javac GCTest.java
java -Xms60m -Xmx60m -XX:SurvivorRatio=8 GCTest

将代码编译运行。

jmap -dump:format=b,file=D:/dump1.hprof 47948

运行程序后通过jps查看pid进程,最终该程序会产生内存溢出,在问题出现之前使用上述命令导出dump文件即可。

在这里插入图片描述

当程序发生内存溢出退出系统时,一些瞬时信息都随着程序的终止而消失,而重现OOM问题往往比较困难或者耗时。

若能在OOM时,自动导出dump文件就显得非常迫切。可以配置JVM参数“-XX:+HeapDumpOnOutOfMemoryError:​”使程序发生OOM时,导出应用程序的当前堆快照。

-Xms60m
-Xmx60m
-XX:+HeapDumpOnOutOfMemoryError
-XX:HeapDumpPath=d:/autoDump.hprof
java -Xms60m -Xmx60m -XX:SurvivorRatio=8 -XX:+HeapDumpOnOutOfMemoryError  -XX:HeapDumpPath=d:/autoDump.hprof  GCTest
(2)-heap选项:显示堆内存相关信息。

命令如下。

#50380表示当前进程ID
jmap -heap 51376

输出运行结果示例如下:

C:\Users\Administrator>jmap -heap 51376
Attaching to process ID 51376, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 25.275-b01using thread-local object allocation.
Parallel GC with 10 thread(s)Heap Configuration:MinHeapFreeRatio         = 0MaxHeapFreeRatio         = 100MaxHeapSize              = 62914560 (60.0MB)NewSize                  = 20971520 (20.0MB)MaxNewSize               = 20971520 (20.0MB)OldSize                  = 41943040 (40.0MB)NewRatio                 = 2SurvivorRatio            = 8MetaspaceSize            = 21807104 (20.796875MB)CompressedClassSpaceSize = 1073741824 (1024.0MB)MaxMetaspaceSize         = 17592186044415 MBG1HeapRegionSize         = 0 (0.0MB)Heap Usage:
PS Young Generation
Eden Space:capacity = 16777216 (16.0MB)used     = 10362656 (9.882598876953125MB)free     = 6414560 (6.117401123046875MB)61.76624298095703% used
From Space:capacity = 2097152 (2.0MB)used     = 0 (0.0MB)free     = 2097152 (2.0MB)0.0% used
To Space:capacity = 2097152 (2.0MB)used     = 0 (0.0MB)free     = 2097152 (2.0MB)0.0% used
PS Old Generationcapacity = 41943040 (40.0MB)used     = 41853832 (39.91492462158203MB)free     = 89208 (0.08507537841796875MB)99.78731155395508% used

打印heap的概要信息、GC使用的算法、heap的配置和使用情况,可以判断当前堆内存使用情况以及垃圾回收情况。

该 Java 应用几乎耗尽了所有内存,老年代Old Generation)已被填满 99.78%,应用处于严重的内存不足状态,随时可能因无法分配新对象而触发 Full GC,甚至抛出 OutOfMemoryError 导致进程崩溃。

(3)-hiso选项:显示堆中对象的统计信息。

命令如下:

#1520表示当前进程ID
jmap -histo 1520

输出示例如下:

 num     #instances         #bytes  class name
----------------------------------------------1:           805       30382712  [B2:           272         769168  [I3:          5066         610672  [C4:          4358         104592  java.lang.String5:           595          68160  java.lang.Class6:          1191          57744  [Ljava.lang.Object;7:           792          31680  java.util.TreeMap$Entry8:           622          24880  java.util.LinkedHashMap$Entry9:           429          22352  [Ljava.lang.String;10:            29          10608  [Ljava.util.HashMap$Node;11:           330          10560  java.util.HashMap$Node12:           229           7328  java.util.Hashtable$Entry13:            75           5400  java.lang.reflect.Field14:           107           4280  java.lang.ref.SoftReference15:           256           4096  java.lang.Integer16:           130           3120  java.lang.StringBuffer17:             8           3008  java.lang.Thread18:            43           2752  java.net.URL19:           114           2736  java.lang.StringBuilder20:            15           2624  [Ljava.util.Hashtable$Entry;21:             5           2600  [J22:             2           2392  [[Ljava.lang.Object;23:            28           2240  [S24:            70           2240  java.util.concurrent.ConcurrentHashMap$Node25:             2           2080  [[C26:            60           1920  java.io.File27:            39           1872  sun.util.locale.LocaleObjectCache$CacheEntry28:            16           1664  [Ljava.util.concurrent.ConcurrentHashMap$Node;29:             1           1568  [[B30:            16           1280  java.lang.reflect.Constructor31:            20           1280  java.util.concurrent.ConcurrentHashMap32:             2           1064  [Ljava.lang.invoke.MethodHandle;33:            19           1064  sun.misc.URLClassPath$JarLoader34:             1           1040  [Ljava.lang.Integer;35:            26           1040  java.io.ObjectStreamField36:            20            960  java.util.HashMap37:            16            896  java.lang.Class$ReflectionData38:            21            840  sun.util.locale.BaseLocale$Key39:            33            792  java.io.ExpiringCache$Entry40:            45            720  java.lang.Object41:            19            608  java.util.Locale42:            19            608  sun.util.locale.BaseLocale43:            21            504  java.util.Locale$LocaleKey44:            12            480  java.security.AccessControlContext45:             7            424  [Ljava.lang.reflect.Field;46:            17            408  sun.misc.MetaIndex47:             1            384  java.lang.ref.Finalizer$FinalizerThread48:            16            384  java.net.Parts49:             6            384  java.nio.DirectByteBuffer50:             1            376  java.lang.ref.Reference$ReferenceHandler51:             6            336  java.nio.DirectLongBufferU52:            17            320  [Ljava.lang.Class;53:            10            320  java.lang.OutOfMemoryError54:             8            320  java.lang.ref.Finalizer55:            10            320  java.lang.ref.ReferenceQueue56:            10            288  [Ljava.io.ObjectStreamField;57:            12            288  java.util.ArrayList58:             6            288  java.util.Hashtable59:             7            280  java.io.FileDescriptor60:             5            280  java.util.ResourceBundle$CacheKey61:             5            280  sun.util.calendar.ZoneInfo62:             8            256  java.util.Vector63:             4            256  sun.nio.cs.ext.DoubleByte$Encoder64:             3            240  [Ljava.util.WeakHashMap$Entry;65:             2            240  [[Ljava.lang.String;66:             5            240  java.nio.HeapByteBuffer67:             4            224  java.util.LinkedHashMap68:             4            224  sun.nio.cs.ext.DoubleByte$Decoder69:             5            200  java.util.WeakHashMap$Entry70:             8            192  [Ljava.lang.reflect.Constructor;71:            12            192  java.lang.ref.ReferenceQueue$Lock72:             4            192  java.nio.HeapCharBuffer73:             4            192  java.util.TreeMap74:             8            192  sun.misc.URLClassPath$375:             8            192  sun.reflect.NativeConstructorAccessorImpl76:             2            160  [Ljava.lang.ThreadLocal$ThreadLocalMap$Entry;77:             5            160  java.io.FileInputStream78:             4            160  java.security.PrivilegedActionException79:             4            160  java.security.ProtectionDomain80:             5            160  java.util.ResourceBundle$LoaderReference81:             5            160  sun.util.locale.provider.LocaleProviderAdapter$Type82:             3            144  java.util.Hashtable$Enumerator83:             3            144  java.util.Properties84:             3            144  java.util.WeakHashMap85:             6            144  sun.misc.PerfCounter86:             3            144  sun.misc.URLClassPath87:             3            144  sun.nio.cs.StreamEncoder88:             6            144  sun.security.action.GetPropertyAction89:             2            128  java.io.ExpiringCache$190:             4            128  java.lang.ThreadLocal$ThreadLocalMap$Entry91:             4            128  java.lang.ref.WeakReference92:             4            128  java.security.CodeSource93:             4            128  java.util.Stack94:             8            128  sun.reflect.DelegatingConstructorAccessorImpl95:             3            120  java.io.BufferedWriter96:             5            120  java.util.Collections$UnmodifiableRandomAccessList97:             5            120  sun.nio.fs.WindowsPathType98:             2             96  java.lang.ThreadGroup99:             2             96  java.util.ResourceBundle$BundleReference100:             1             96  sun.misc.Launcher$AppClassLoader101:             1             96  sun.util.calendar.Gregorian$Date102:             1             88  java.lang.reflect.Method103:             1             88  sun.misc.Launcher$ExtClassLoader104:             2             80  [Lsun.util.locale.provider.LocaleProviderAdapter$Type;105:             2             80  java.io.BufferedInputStream106:             2             80  java.io.ExpiringCache107:             2             80  java.util.ServiceLoader$LazyIterator108:             2             80  sun.misc.URLClassPath$1109:             2             80  sun.misc.URLClassPath$2110:             2             80  sun.util.locale.LanguageTag111:             3             72  java.io.OutputStreamWriter112:             3             72  java.lang.Class$1113:             3             72  java.lang.RuntimePermission114:             3             72  java.util.Arrays$ArrayList115:             3             72  java.util.LinkedList$Node116:             1             72  java.util.ResourceBundle$RBClassLoader117:             3             72  java.util.concurrent.atomic.AtomicLong118:             1             72  sun.util.locale.provider.JRELocaleProviderAdapter119:             2             64  [Ljava.lang.Thread;120:             4             64  [Ljava.security.Principal;121:             2             64  java.io.DataInputStream122:             2             64  java.io.FileNotFoundException123:             2             64  java.io.FileOutputStream124:             2             64  java.io.PrintStream125:             2             64  java.lang.ClassValue$Entry126:             2             64  java.lang.StringCoding$StringDecoder127:             2             64  java.lang.StringCoding$StringEncoder128:             2             64  java.lang.VirtualMachineError129:             2             64  java.lang.ref.ReferenceQueue$Null130:             4             64  java.security.ProtectionDomain$Key131:             2             64  java.util.ArrayList$Itr132:             2             64  java.util.LinkedHashMap$LinkedEntryIterator133:             2             64  java.util.ServiceLoader134:             1             56  sun.nio.cs.ISO_8859_1$Encoder135:             1             48  [Ljava.io.File;136:             1             48  [Ljava.net.URL;137:             2             48  [Ljava.util.Enumeration;138:             2             48  java.io.BufferedOutputStream139:             1             48  java.io.BufferedReader140:             2             48  java.io.File$PathStatus141:             3             48  java.lang.ThreadLocal142:             2             48  java.lang.ThreadLocal$ThreadLocalMap143:             2             48  java.net.URLClassLoader$3144:             2             48  java.nio.charset.CoderResult145:             3             48  java.nio.charset.CodingErrorAction146:             2             48  java.util.Collections$SynchronizedSet147:             3             48  java.util.HashSet148:             2             48  java.util.ServiceLoader$1149:             1             48  java.util.StringTokenizer150:             2             48  sun.misc.CompoundEnumeration151:             2             48  sun.misc.FileURLMapper152:             2             48  sun.misc.NativeSignalHandler153:             2             48  sun.misc.Signal154:             3             48  sun.net.www.protocol.jar.Handler155:             1             48  sun.nio.cs.StreamDecoder156:             1             48  sun.util.locale.provider.LocaleResources$ResourceReference157:             1             48  sun.util.resources.TimeZoneNames158:             1             48  sun.util.resources.en.TimeZoneNames_en159:             1             40  [Lsun.nio.fs.WindowsPathType;160:             1             40  java.lang.ClassLoader$NativeLibrary161:             1             40  java.util.ResourceBundle$1162:             1             40  sun.nio.cs.StandardCharsets$Aliases163:             1             40  sun.nio.cs.StandardCharsets$Cache164:             1             40  sun.nio.cs.StandardCharsets$Classes165:             1             40  sun.nio.cs.ext.ExtendedCharsets166:             1             32  [Ljava.lang.OutOfMemoryError;167:             2             32  [Ljava.lang.StackTraceElement;168:             1             32  [Ljava.lang.ThreadGroup;169:             1             32  java.io.ByteArrayInputStream170:             2             32  java.io.FileInputStream$1171:             1             32  java.io.FilePermission172:             1             32  java.io.WinNTFileSystem173:             1             32  java.lang.ArithmeticException174:             2             32  java.lang.Boolean175:             2             32  java.lang.ClassLoader$2176:             1             32  java.lang.NullPointerException177:             2             32  java.net.URLClassLoader$3$1178:             2             32  java.nio.ByteOrder179:             1             32  java.security.BasicPermissionCollection180:             1             32  java.security.Permissions181:             2             32  java.util.LinkedHashMap$LinkedEntrySet182:             2             32  java.util.LinkedHashMap$LinkedKeySet183:             1             32  java.util.LinkedList184:             2             32  java.util.concurrent.atomic.AtomicInteger185:             1             32  java.util.concurrent.atomic.AtomicReferenceFieldUpdater$AtomicReferenceFieldUpdaterImpl186:             2             32  sun.misc.URLClassPath$JarLoader$1187:             1             32  sun.nio.cs.StandardCharsets188:             1             32  sun.nio.fs.WindowsFileSystem189:             1             32  sun.util.locale.provider.LocaleResources190:             1             32  sun.util.locale.provider.LocaleServiceProviderPool191:             1             24  [Ljava.io.File$PathStatus;192:             1             24  [Ljava.lang.ClassValue$Entry;193:             1             24  [Ljava.lang.reflect.Method;194:             1             24  [Lsun.launcher.LauncherHelper;195:             1             24  java.io.ByteArrayOutputStream196:             1             24  java.io.FilePermissionCollection197:             1             24  java.io.FileReader198:             1             24  java.lang.ClassValue$Version199:             1             24  java.lang.invoke.MethodHandleImpl$4200:             1             24  java.lang.reflect.ReflectPermission201:             1             24  java.util.BitSet202:             1             24  java.util.Collections$EmptyMap203:             1             24  java.util.Collections$SetFromMap204:             1             24  java.util.Collections$UnmodifiableCollection$1205:             1             24  java.util.Date206:             1             24  java.util.Locale$Cache207:             1             24  java.util.ResourceBundle$Control$CandidateListCache208:             1             24  sun.launcher.LauncherHelper209:             1             24  sun.misc.URLClassPath$FileLoader210:             1             24  sun.nio.cs.ISO_8859_1211:             1             24  sun.nio.cs.Surrogate$Parser212:             1             24  sun.nio.cs.ext.GBK213:             1             24  sun.nio.cs.ext.MS936214:             1             24  sun.util.locale.BaseLocale$Cache215:             1             24  sun.util.locale.provider.SPILocaleProviderAdapter$1216:             1             24  sun.util.locale.provider.TimeZoneNameProviderImpl217:             1             24  sun.util.resources.LocaleData$1218:             1             16  [Ljava.lang.Throwable;219:             1             16  [Ljava.security.cert.Certificate;220:             1             16  [Lsun.util.calendar.ZoneInfoFile$ZoneOffsetTransitionRule;221:             1             16  java.io.FileDescriptor$1222:             1             16  java.lang.CharacterDataLatin1223:             1             16  java.lang.ClassValue$Identity224:             1             16  java.lang.Runtime225:             1             16  java.lang.String$CaseInsensitiveComparator226:             1             16  java.lang.System$2227:             1             16  java.lang.Terminator$1228:             1             16  java.lang.invoke.MemberName$Factory229:             1             16  java.lang.invoke.MethodHandleImpl$2230:             1             16  java.lang.invoke.MethodHandleImpl$3231:             1             16  java.lang.ref.Reference$1232:             1             16  java.lang.ref.Reference$Lock233:             1             16  java.lang.reflect.ReflectAccess234:             1             16  java.net.URLClassLoader$7235:             1             16  java.nio.Bits$1236:             1             16  java.nio.charset.CoderResult$1237:             1             16  java.nio.charset.CoderResult$2238:             1             16  java.security.ProtectionDomain$2239:             1             16  java.security.ProtectionDomain$JavaSecurityAccessImpl240:             1             16  java.util.Collections$EmptyIterator241:             1             16  java.util.Collections$EmptyList242:             1             16  java.util.Collections$EmptySet243:             1             16  java.util.Collections$UnmodifiableSet244:             1             16  java.util.Hashtable$EntrySet245:             1             16  java.util.Hashtable$KeySet246:             1             16  java.util.ResourceBundle$Control247:             1             16  java.util.ResourceBundle$RBClassLoader$1248:             1             16  java.util.TimeZone$1249:             1             16  java.util.WeakHashMap$KeySet250:             1             16  java.util.zip.ZipFile$1251:             1             16  sun.misc.ASCIICaseInsensitiveComparator252:             1             16  sun.misc.Launcher253:             1             16  sun.misc.Launcher$BootClassPathHolder$1254:             1             16  sun.misc.Launcher$Factory255:             1             16  sun.misc.Perf256:             1             16  sun.misc.Unsafe257:             1             16  sun.net.www.protocol.file.Handler258:             1             16  sun.nio.fs.WindowsFileSystemProvider259:             1             16  sun.reflect.ReflectionFactory260:             1             16  sun.util.calendar.Gregorian261:             1             16  sun.util.calendar.ZoneInfoFile$1262:             1             16  sun.util.calendar.ZoneInfoFile$Checksum263:             1             16  sun.util.locale.provider.AuxLocaleProviderAdapter$NullProvider264:             1             16  sun.util.locale.provider.JRELocaleProviderAdapter$1265:             1             16  sun.util.locale.provider.SPILocaleProviderAdapter266:             1             16  sun.util.locale.provider.TimeZoneNameUtility$TimeZoneNameGetter267:             1             16  sun.util.resources.LocaleData268:             1             16  sun.util.resources.LocaleData$LocaleDataResourceBundleControl
Total         16534       32178440

上面结果中,instances表示当前的实例数量;bytes表示对象占用的内存大小;classs name表示类名,按照内存大小逆序排列。

排名第一的类 [B (byte数组) 有 805个实例,却占据了 30,382,712 字节(约 30.38 MB)。

这说明正在创建大量的大型byte数组,这与上面的代码 new byte[1024 * 100](每次分配100KB)完全吻合。

由于jmap将访问堆中的所有对象,为了保证在此过程中不被应用线程干扰,jmap需要借助安全点机制,让所有线程不改变堆中数据的状态。

也就是说,由jmap导出的堆快照必定是安全点位置的。这可能导致基于该快照的分析结果存在偏差。例如,假设在编译生成的机器码中,某些对象的生命周期在两个安全点之间,那么:live选项将无法探知到这些对象。

另外如果某个线程长时间无法跑到安全点,jmap将一直等待下去。

与前面讲的jstat不同,垃圾收集器会主动将jstat所需要的摘要数据保存至固定位置中,而jstat只需要直接读取即可。

(六)jhat:JDK自带堆分析工具

jhat(JVM Heap Analysis Tool)命令一般与jmap命令搭配使用,用于分析jmap生成的dump文件(堆转储快照)​。

jhat内置了一个微型的HTTP/HTML服务器,生成dump文件的分析结果后,用户可以在浏览器中查看分析结果。

使用了jhat命令,就启动了一个http服务,端口是7000,即通过访问http://localhost:7000/就可以在浏览器中查看结果。

jhat命令在JDK9中已经被删除,官方建议用VisualVM代替。实际工作中一般不会直接在生产服务器使用jhat分析dump文件。

jhat的基本使用语法如下。

     jhat  [ options ] [ hostid ]

1.[ options ]选项说明

jhat工具[options]主要选项如表所示。

在这里插入图片描述
下面使用jhat命令分析jmap导出的dump文件,命令如下。

jhat d:\autoDump.hprof

当界面出现Server is ready时,就可以在浏览器访问http://localhost:7000/了,如图:
在这里插入图片描述
分析结果默认以包的形式分组展示,当分析内存溢出或者内存泄漏问题的时候一般会用到“Show heap histogram”功能,它的作用和jmap –histo一样,如图所示。
在这里插入图片描述

在这里可以找到内存中使用空间最大的对象。通常导出的堆快照信息非常大,可能很难通过页面上简单的链接索引找到想要的信息。

为此,jhat还支持使用OQL(Object Query Language)语句对堆快照进行查询。执行OQL语言的界面非常简洁。

单击“Execute Object Query Language(OQL)query”即可进入OQL查询页面,它是一种类似SQL的语法,可以对内存中的对象进行查询统计,例如代码清单,查询了内存中长度大于500的字符串。

select s from java.lang.String s where s.value.length >500

在这里插入图片描述

平常使用jhat命令的频率并不高,所以此处也不再过多赘述。

(七)jstack:打印JVM中线程快照

jstack(JVM Stack Trace)用于生成JVM指定进程当前时刻的线程快照(Thread Dump),方便用户跟踪JVM堆栈信息。

线程快照就是当前JVM内指定进程的每一条线程正在执行的方法堆栈的集合。

生成线程快照的作用是可用于定位线程出现长时间停顿的原因,如线程间死锁、死循环、请求外部资源导致的长时间等待等问题,这些都是导致线程长时间停顿的常见原因。当线程出现停顿时,就可以用jstack显示各个线程调用的堆栈情况。

在这里插入图片描述
其中线程的Deadlock、Waiting on condition、Waiting on monitor entry以及Blocked状态需要在分析线程栈的时候重点关注。

jstack [ option ] <pid>

1.使用案例

代码清单21-4演示了线程死锁,使用jstack命令观察线程状态

import java.util.ArrayList;public class ThreadDeadlock {public static void main(String[] args) {StringBuilder s1 = new StringBuilder();StringBuilder s2 = new StringBuilder();new Thread() {@Overridepublic void run() {synchronized (s1) {s1.append("a");s2.append("1");try {Thread.sleep(100);} catch (InterruptedException e) {e.printStackTrace();}synchronized (s2) {s1.append("b");s2.append("2");System.out.println(s1);System.out.println(s2);}}}}.start();new Thread(new Runnable() {@Overridepublic void run() {synchronized (s2) {s1.append("c");s2.append("3");try {Thread.sleep(100);} catch (InterruptedException e) {e.printStackTrace();}synchronized (s1) {s1.append("d");s2.append("4");System.out.println(s1);System.out.println(s2);}}}}).start();try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}
}

上面例子很简单,启动了两个线程,分别获取对方的资源,如此造成死锁。下面启动程序,使用jstack命令查看线程状态。

输出结果如下:

C:\Users\Administrator>jstack 14360
2025-09-16 11:51:51
Full thread dump OpenJDK 64-Bit Server VM (25.275-b01 mixed mode):"DestroyJavaVM" #14 prio=5 os_prio=0 tid=0x0000027731745000 nid=0xba00 waiting on condition [0x0000000000000000]java.lang.Thread.State: RUNNABLE"Thread-1" #13 prio=5 os_prio=0 tid=0x000002773159e800 nid=0x4f50 waiting for monitor entry [0x000000a7144ff000]java.lang.Thread.State: BLOCKED (on object monitor)at ThreadDeadlock$2.run(ThreadDeadlock.java:41)- waiting to lock <0x000000071939b450> (a java.lang.StringBuilder)- locked <0x000000071939b498> (a java.lang.StringBuilder)at java.lang.Thread.run(Thread.java:748)"Thread-0" #12 prio=5 os_prio=0 tid=0x0000027731517000 nid=0xbbf0 waiting for monitor entry [0x000000a7143ff000]java.lang.Thread.State: BLOCKED (on object monitor)at ThreadDeadlock$1.run(ThreadDeadlock.java:20)- waiting to lock <0x000000071939b498> (a java.lang.StringBuilder)- locked <0x000000071939b450> (a java.lang.StringBuilder)"Service Thread" #11 daemon prio=9 os_prio=0 tid=0x00000277313e2000 nid=0xb428 runnable [0x0000000000000000]java.lang.Thread.State: RUNNABLE"C1 CompilerThread3" #10 daemon prio=9 os_prio=2 tid=0x00000277313e1800 nid=0xa0a0 waiting on condition [0x0000000000000000]java.lang.Thread.State: RUNNABLE"C2 CompilerThread2" #9 daemon prio=9 os_prio=2 tid=0x00000277313e0800 nid=0xad8c waiting on condition [0x0000000000000000]java.lang.Thread.State: RUNNABLE"C2 CompilerThread1" #8 daemon prio=9 os_prio=2 tid=0x00000277313e0000 nid=0xa738 waiting on condition [0x0000000000000000]java.lang.Thread.State: RUNNABLE"C2 CompilerThread0" #7 daemon prio=9 os_prio=2 tid=0x00000277313de800 nid=0xbffc waiting on condition [0x0000000000000000]java.lang.Thread.State: RUNNABLE"Monitor Ctrl-Break" #6 daemon prio=5 os_prio=0 tid=0x00000277313db000 nid=0xb78c runnable [0x000000a713cfe000]java.lang.Thread.State: RUNNABLEat java.net.SocketInputStream.socketRead0(Native Method)at java.net.SocketInputStream.socketRead(SocketInputStream.java:116)at java.net.SocketInputStream.read(SocketInputStream.java:171)at java.net.SocketInputStream.read(SocketInputStream.java:141)at sun.nio.cs.StreamDecoder.readBytes(StreamDecoder.java:284)at sun.nio.cs.StreamDecoder.implRead(StreamDecoder.java:326)at sun.nio.cs.StreamDecoder.read(StreamDecoder.java:178)- locked <0x0000000719553e48> (a java.io.InputStreamReader)at java.io.InputStreamReader.read(InputStreamReader.java:184)at java.io.BufferedReader.fill(BufferedReader.java:161)at java.io.BufferedReader.readLine(BufferedReader.java:324)- locked <0x0000000719553e48> (a java.io.InputStreamReader)at java.io.BufferedReader.readLine(BufferedReader.java:389)at com.intellij.rt.execution.application.AppMainV2$1.run(AppMainV2.java:55)"Attach Listener" #5 daemon prio=5 os_prio=2 tid=0x000002772dbd2800 nid=0x182c waiting on condition [0x0000000000000000]java.lang.Thread.State: RUNNABLE"Signal Dispatcher" #4 daemon prio=9 os_prio=2 tid=0x000002772dbde000 nid=0xc998 runnable [0x0000000000000000]java.lang.Thread.State: RUNNABLE"Finalizer" #3 daemon prio=8 os_prio=1 tid=0x000002772dba4000 nid=0xaff0 in Object.wait() [0x000000a7139ff000]java.lang.Thread.State: WAITING (on object monitor)at java.lang.Object.wait(Native Method)- waiting on <0x0000000716d08ee0> (a java.lang.ref.ReferenceQueue$Lock)at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:144)- locked <0x0000000716d08ee0> (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=0x000002772db9a800 nid=0xc6c0 in Object.wait() [0x000000a7138fe000]java.lang.Thread.State: WAITING (on object monitor)at java.lang.Object.wait(Native Method)- waiting on <0x0000000716d06c00> (a java.lang.ref.Reference$Lock)at java.lang.Object.wait(Object.java:502)at java.lang.ref.Reference.tryHandlePending(Reference.java:191)- locked <0x0000000716d06c00> (a java.lang.ref.Reference$Lock)at java.lang.ref.Reference$ReferenceHandler.run(Reference.java:153)"VM Thread" os_prio=2 tid=0x00000277096ae000 nid=0xb898 runnable"GC task thread#0 (ParallelGC)" os_prio=0 tid=0x000002770960f000 nid=0x6a8c runnable"GC task thread#1 (ParallelGC)" os_prio=0 tid=0x0000027709610800 nid=0xba3c runnable"GC task thread#2 (ParallelGC)" os_prio=0 tid=0x0000027709615000 nid=0xc784 runnable"GC task thread#3 (ParallelGC)" os_prio=0 tid=0x0000027709617000 nid=0xa9ec runnable"GC task thread#4 (ParallelGC)" os_prio=0 tid=0x0000027709619800 nid=0xb468 runnable"GC task thread#5 (ParallelGC)" os_prio=0 tid=0x000002770961a800 nid=0x7af0 runnable"GC task thread#6 (ParallelGC)" os_prio=0 tid=0x000002770961e000 nid=0xc0dc runnable"GC task thread#7 (ParallelGC)" os_prio=0 tid=0x000002770961f000 nid=0xa594 runnable"GC task thread#8 (ParallelGC)" os_prio=0 tid=0x0000027709620800 nid=0xa570 runnable"GC task thread#9 (ParallelGC)" os_prio=0 tid=0x0000027709622000 nid=0xc12c runnable"VM Periodic Task Thread" os_prio=2 tid=0x0000027731403800 nid=0x65e8 waiting on conditionJNI global references: 12Found one Java-level deadlock:
=============================
"Thread-1":waiting to lock monitor 0x00000277319c41c8 (object 0x000000071939b450, a java.lang.StringBuilder),which is held by "Thread-0"
"Thread-0":waiting to lock monitor 0x000002772dba3b48 (object 0x000000071939b498, a java.lang.StringBuilder),which is held by "Thread-1"Java stack information for the threads listed above:
===================================================
"Thread-1":at ThreadDeadlock$2.run(ThreadDeadlock.java:41)- waiting to lock <0x000000071939b450> (a java.lang.StringBuilder)- locked <0x000000071939b498> (a java.lang.StringBuilder)at java.lang.Thread.run(Thread.java:748)
"Thread-0":at ThreadDeadlock$1.run(ThreadDeadlock.java:20)- waiting to lock <0x000000071939b498> (a java.lang.StringBuilder)- locked <0x000000071939b450> (a java.lang.StringBuilder)Found 1 deadlock.

从上面结果中可以发现,Thread-1线程和Thread-0线程互相等待对方的资源,问题代码出现“ThreadDeadLock$2.run()”行。

在死锁情况出现时,可以很方便地帮助定位到问题。也可以通过Thread.getAllStackTraces()方法获取所有线程的状态

import java.util.Map;
import java.util.Set;public class AllStackTrace {public static void main(String[] args) {Map<Thread, StackTraceElement[]> all = Thread.getAllStackTraces();Set<Map.Entry<Thread, StackTraceElement[]>> entries = all.entrySet();for (Map.Entry<Thread, StackTraceElement[]> en : entries) {Thread t = en.getKey();StackTraceElement[] v = en.getValue();System.out.println("【Thread name is :" + t.getName() + "】");for (StackTraceElement s : v) {System.out.println("\t" + s.toString());}}}
}

运行结果可以看到各个线程的状态。

【Thread name is :Monitor Ctrl-Break】java.net.Socket.setImpl(Socket.java:521)java.net.Socket.<init>(Socket.java:442)java.net.Socket.<init>(Socket.java:229)com.intellij.rt.execution.application.AppMainV2$1.run(AppMainV2.java:52)
【Thread name is :main】java.lang.Thread.dumpThreads(Native Method)java.lang.Thread.getAllStackTraces(Thread.java:1610)AllStackTrace.main(AllStackTrace.java:6)
【Thread name is :Attach Listener】
【Thread name is :Reference Handler】java.lang.Object.wait(Native Method)java.lang.Object.wait(Object.java:502)java.lang.ref.Reference.tryHandlePending(Reference.java:191)java.lang.ref.Reference$ReferenceHandler.run(Reference.java:153)
【Thread name is :Signal Dispatcher】
【Thread name is :Finalizer】java.lang.Object.wait(Native Method)java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:144)java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:165)java.lang.ref.Finalizer$FinalizerThread.run(Finalizer.java:216)
(1)Monitor Ctrl-Break
【Thread name is :Monitor Ctrl-Break】java.net.Socket.setImpl(Socket.java:521)java.net.Socket.<init>(Socket.java:442)java.net.Socket.<init>(Socket.java:229)com.intellij.rt.execution.application.AppMainV2$1.run(AppMainV2.java:52)
  • 作用:这是 IntelliJ IDEA(或其他 IDE)注入的一个特殊线程,用于实现 Ctrl + Break(或 Ctrl + C)中断功能。
  • 它监听控制台输入,当用户按下中断键时,它可以捕获信号并触发线程 dump 或中断程序执行。
  • 常见于在 IDE 中运行 Java 程序时。
  • 堆栈说明:它正在使用 Socket 与 IDE 的运行时通信模块进行通信(用于传输中断信号或性能数据)。

注意:如果你在命令行运行程序,通常不会有这个线程。

(2)main
【Thread name is :main】java.lang.Thread.dumpThreads(Native Method)java.lang.Thread.getAllStackTraces(Thread.java:1610)AllStackTrace.main(AllStackTrace.java:6)
  • 作用:这是 Java 程序的主执行线程,所有程序逻辑默认从这里开始。
  • 在你的代码中,正是 main 线程调用了 Thread.getAllStackTraces() 来获取所有线程的堆栈。
  • 堆栈说明
    • dumpThreads(Native Method):本地方法,用于获取所有线程的堆栈。
    • getAllStackTraces():Java 层调用。
    • AllStackTrace.main():你的代码入口。

这是你的程序逻辑运行的地方。

(3)Attach Listener
【Thread name is :Attach Listener】
  • 作用:这是一个 JVM 内部线程,用于支持 动态 attach 机制
  • 允许外部工具(如 jstack, jmap, jconsole, VisualVM 等)通过 VirtualMachine.attach(pid) 连接到正在运行的 JVM。
  • 例如,当你运行 jstack 12345 时,就是通过这个线程建立连接并获取线程 dump。
  • 它通常在需要诊断时才被激活。

安全提示:在生产环境中,可以通过 -XX:+DisableAttachMechanism 禁用此功能以提高安全性。


(4)Reference Handler
【Thread name is :Reference Handler】java.lang.Object.wait(Native Method)java.lang.Object.wait(Object.java:502)java.lang.ref.Reference.tryHandlePending(Reference.java:191)java.lang.ref.Reference$ReferenceHandler.run(Reference.java:153)
  • 作用:处理 Java 中的 引用对象(Reference),比如:
    • SoftReference(软引用)
    • WeakReference(弱引用)
    • PhantomReference(虚引用)
  • 当这些引用指向的对象被 GC 回收后,Reference Handler 会将它们加入到对应的 ReferenceQueue 中,供程序后续处理。
  • 是 JVM 垃圾回收机制的重要组成部分。

例如:WeakHashMap 就依赖这个线程来清理失效的条目。

(5)Finalizer
【Thread name is :Finalizer】java.lang.Object.wait(Native Method)java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:144)java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:165)java.lang.ref.Finalizer$FinalizerThread.run(Finalizer.java:216)
  • 作用:负责调用对象的 finalize() 方法(如果该类重写了此方法)。
  • 当一个对象被 GC 标记为可回收,且该类有 finalize() 方法时,JVM 会将其放入一个队列,由 Finalizer 线程异步调用其 finalize()
  • 注意finalize() 已被标记为 @Deprecated(从 Java 9 开始),不推荐使用,因为它不可控、性能差、可能导致内存泄漏。

建议使用 try-with-resources 或手动清理资源,而不是依赖 finalize()

(6) Signal Dispatcher
【Thread name is :Signal Dispatcher】
  • 作用:处理操作系统发送给 JVM 的 信号(Signals)
  • 例如:
    • SIGQUIT(Ctrl + \):触发线程 dump
    • SIGTERM:优雅关闭
    • SIGINT(Ctrl + C):中断程序
  • 它是一个 JVM 内部线程,负责将这些信号转发给相应的处理逻辑。

例如:你按 Ctrl + \ 时,Signal Dispatcher 会触发打印所有线程的堆栈。

线程名称作用是否重要
main程序主执行线程✅ 必须
Reference Handler处理软/弱/虚引用的回收✅ 核心 GC 组件
Finalizer调用对象的 finalize() 方法⚠️ 已废弃,慎用
Attach Listener支持 jstackjmap 等工具 attach 到 JVM✅ 诊断必备
Signal Dispatcher处理系统信号(如 Ctrl+C)✅ 运行时支持
Monitor Ctrl-BreakIDE 注入,支持中断和监控🛠️ 仅 IDE 环境存在

(八)jcmd:多功能命令行

在JDK1.7以后,新增了一个命令行工具jcmd。

它是一个多功能的工具,可以用来实现前面除了jstat之外所有命令的功能,比如用它来导出堆、内存使用、查看Java进程、导出线程信息、执行GC、JVM运行时间等。

jcmd拥有jmap的大部分功能,并且官方也推荐使用jcmd命令代替jmap命令。至于jstat的功能,虽然jcmd复制了jstat的部分代码,并支持通过PerfCounter.print子命令来打印所有的Performance Counter,但是它没有保留jstat的输出格式,也没有重复打印的功能。

jcmd的基本使用语法如表所示。

在这里插入图片描述

1. jcmd pid help选项:针对指定的进程,列出支持的所有命令

针对每一个进程,jcmd可以使用help命令列出它们所支持的命令,如下所示。

jcmd  25935  help

运行结果如下。

25935:
The following commands are available:
Compiler.CodeHeap_Analytics
Compiler.codecache
Compiler.codelist
Compiler.directives_add
Compiler.directives_clear
Compiler.directives_print
Compiler.directives_remove
Compiler.perfmap
Compiler.queue
GC.class_histogram
GC.finalizer_info
GC.heap_dump
GC.heap_info
GC.run
GC.run_finalization
JFR.check
JFR.configure
JFR.dump
JFR.start
JFR.stop
JVMTI.agent_load
JVMTI.data_dump
ManagementAgent.start
ManagementAgent.start_local
ManagementAgent.status
ManagementAgent.stop
System.trim_native_heap
Thread.print
VM.cds
VM.class_hierarchy
VM.classloader_stats
VM.classloaders
VM.command_line
VM.dynlibs
VM.events
VM.flags
VM.info
VM.log
VM.metaspace
VM.native_memory
VM.print_touched_methods
VM.set_flag
VM.stringtable
VM.symboltable
VM.system_properties
VM.systemdictionary
VM.uptime
VM.version
helpFor more information about a specific command use 'help <command>'.

上面罗列的是进程号为25935的JVM进程支持的jcmd相关命令操作,jcmd pid [options]中的options就是上面列出的所有命令参数选项。下面介绍常用的几个参数选项。

2.查看JVM启动时间VM.uptime

jcmd 25935 VM.uptime

在这里插入图片描述

3.打印线程栈信息

jcmd 25935 Thread.print

在这里插入图片描述

(九)jstatd:远程主机信息收集

之前的指令只涉及监控本机的Java应用程序,而在这些工具中,一些监控工具也支持对远程计算机的监控(如jps、jstat)​。

为了启用远程监控,则需要配合使用jstatd工具。

命令jstatd是一个RMI服务端程序,它的作用相当于代理服务器,建立本地计算机与远程监控工具的通信。

jstatd服务器将本机的Java应用程序信息传递到远程计算机。

在这里插入图片描述
直接打开jstatd服务器可能会抛出访问拒绝异常,这是因为jstatd程序没有足够的权限,如图所示。

在这里插入图片描述

http://www.dtcms.com/a/591244.html

相关文章:

  • 网站开发职业要求3d效果图怎么制作用什么软件
  • 太平洋网站开发建设产品信息网站
  • 最新网站开发需求文档网络营销顾问是干嘛的
  • 黄浦区网站建设公司常州模板网站建设咨询
  • 中国建设银行网站成都第七支行上海松一网站建设
  • 网站建设解决方案有哪些app图片怎么制作
  • 佛山企业网站设计网络工程师的前景
  • 无锡网站建设公司研发小程序成本
  • 深圳电商网站设计公司wordpress扩展字段
  • 我想学网站建设需要选择什么书wordpress单本小说
  • 买机箱网站怎么用qq邮箱做网站
  • 深汕特别合作区招聘黑帽seo
  • 网站优化竞争对手分析网站基础服务
  • 建站所有步骤做一个网站先做前段 还是后端
  • 【Java】Java 中 @Resource 与 @Autowired 的区别详解
  • 重庆招聘一般上什么网站金空间网站
  • 网站建设需要上传数据库吗专业的外贸网站建设公司
  • 谷歌认证合作伙伴网站建设顺德网站设计
  • 【MySQL | 基础】DDL语句以及数据类型
  • 电商网站的二级菜单怎么做广东深圳旅游必去十大景点
  • Flow Matching|什么是“预测速度场 vt=ε−x”?
  • 福田公司网站建设福田做棋牌网站建设多少钱
  • 网站开发交接协议书郑州做企业网站的
  • 佟年给韩商言做的网站郑州设计工作室
  • wordpress网站转app个人网站 可以做论坛吗
  • 网站数据库一般多大服务型网站建设
  • 做的网站第二年续费多钱软件ui设计师
  • 杭州做网站五代理注册公司怎么收费
  • 网站搜索不到公司网站用wordpress建站会不会显得水平差
  • 闽清网站建设临湘网站建设