jvm的运行参数以及参数的设置
节制jvm的内存模型(堆内存)
节制jamp命令的利用以及通过MAT工具进行剖析

节制定位剖析内存溢出的方法
节制jstack命令的利用
节制VisualJVM工具的利用
1、我们为什么要对jvm做优化?在本地开拓环境中我们很少会碰着须要对jvm进行优化的需求,但是到了生产环境,我们 可能将有下面的需求:
运行的运用“卡住了”,日志不输出,程序没有反应做事器的CPU负载溘然升高
在多线程运用下,如何分配线程的数量?
……
在本次课程中,我们将对jvm有更深入的学习,我们不仅要让程序能跑起来,而且是可以 跑的更快!
可以剖析办理在生产环境中所碰着的各种“棘手”的问题。
解释:本套课程利用的jdk版本为1.8。
2、jvm的运行参数在jvm中有很多的参数可以进行设置,这样可以让jvm在各种环境中都能够高效的运行。 绝大部分的参数保持默认即可。
2.1、三种参数类型
jvm的参数类型分为三类,分别是:
标准参数
-help
-version
-X参数 (非标准参数)
-Xint
-Xcomp
-XX参数(利用率较高)
-XX:newSize
-XX:+UseSerialGC
2.2、标准参数
jvm的标准参数,一样平常都是很稳定的,在未来的JVM版本中不会改变,可以利用java -help
检索出所有的标准参数。
[root@node01 ~]# java ‐help用法: java [‐options] class [args...](实行类)或java [‐options] ‐jar jarfile [args...] (实行 jar 文件)个中选项包括:‐d32利用 32 位数据模型 (如果可用)‐d64利用 64 位数据模型 (如果可用)‐server选择 \"大众server\"大众 VM默认 VM 是 server,由于您是在做事器类打算机上运行。‐cp <目录和 zip/jar 文件的类搜索路径>‐classpath <目录和 zip/jar 文件的类搜索路径>用 : 分隔的目录, JAR 档案和 ZIP 档案列表, 用于搜索类文件。‐D<名称>=<值>设置系统属性‐verbose:[class|gc|jni]启器具体输出‐version输出产品版本并退出‐version:<值>警告: 此功能已过期, 将在未来发行版中删除。须要指定的版本才能运行‐showversion输出产品版本并连续‐jre‐restrict‐search | ‐no‐jre‐restrict‐search警告: 此功能已过期, 将在未来发行版中删除。在版本搜索中包括/打消用户专用 JRE‐? ‐help输出此帮助‐X输出非标准选项的帮助‐ea[:<packagename>...|:<classname>]‐enableassertions[:<packagename>...|:<classname>]按指定的粒度启用断言‐da[:<packagename>...|:<classname>]‐disableassertions[:<packagename>...|:<classname>]禁用具有指定粒度的断言‐esa | ‐enablesystemassertions启用系统断言‐dsa | ‐disablesystemassertions禁用系统断言‐agentlib:<libname>[=<选项>]加载本机代理库 <libname>, 例如 ‐agentlib:hprof另请参阅 ‐agentlib:jdwp=help 和 ‐agentlib:hprof=help‐agentpath:<pathname>[=<选项>]按完全路径名加载本机代理库‐javaagent:<jarpath>[=<选项>]加载 Java 编程措辞代理, 请参阅 java.lang.instrument‐splash:<imagepath>利用指定的图像显示启动屏幕
2.2.1、实战
实战1:查看jvm版本
[root@node01 ~]# java ‐versionjava version \"大众1.8.0_141\"大众Java(TM) SE Runtime Environment (build 1.8.0_141‐b15)Java HotSpot(TM) 64‐Bit Server VM (build 25.141‐b15, mixed mode)# ‐showversion参数是表示,先打印版本信息,再实行后面的命令,在调试时非常有用,后面会利用到。
实战2:通过-D设置系统属性参数
public class TestJVM {public static void main(String[] args) {String str = System.getProperty(\"大众str\"大众); if (str == null) {System.out.println(\"大众itcast\"大众);} else {System.out.println(str);}}}
进行编译、测试:
#编译
[root@node01 test]# javac TestJVM.java
#测试
[root@node01 test]# java TestJVM itcast
[root@node01 test]# java ‐Dstr=123 TestJVM
123
2.2.2、-server与-client参数
可以通过-server或-client设置jvm的运行参数。
它们的差异是Server VM的初始堆空间会大一些,默认利用的是并行垃圾回收器,启动慢运行快。
Client VM相对来讲会守旧一些,初始堆空间会小一些,利用串行的垃圾回收器,它的目标是为了让JVM的启动速率更快,但运行速率会比Serverm模式慢些。
JVM在启动的时候会根据硬件和操作系统自动选择利用Server还是Client类型的 JVM。
32位操作系统
如果是Windows系统,不论硬件配置如何,都默认利用Client类型的JVM。
如果是其他操作系统上,机器配置有2GB以上的内存同时有2个以上CPU的话默认利用server模式,否则利用client模式。
64位操作系统
只有server类型,不支持client类型。
测试:
[root@node01 test]# java ‐client ‐showversion TestJVMjava version \"大众1.8.0_141\公众Java(TM) SE Runtime Environment (build 1.8.0_141‐b15)Java HotSpot(TM) 64‐Bit Server VM (build 25.141‐b15, mixed mode)itcast[root@node01 test]# java ‐server ‐showversion TestJVMjava version \"大众1.8.0_141\"大众Java(TM) SE Runtime Environment (build 1.8.0_141‐b15)Java HotSpot(TM) 64‐Bit Server VM (build 25.141‐b15, mixed mode)itcast#由于机器是64位系统,以是不支持client模式
2.2.3、-X参数
jvm的-X参数是非标准参数,在不同版本的jvm中,参数可能会有所不同,可以通过java - X查看非标准参数。
[root@node01 test]# java ‐X‐Xmixed稠浊模式实行 (默认)‐Xint仅阐明模式实行‐Xbootclasspath:<用 : 分隔的目录和 zip/jar 文件>设置搜索路径以勾引类和资源‐Xbootclasspath/a:<用 : 分隔的目录和 zip/jar 文件>附加在勾引类路径末端‐Xbootclasspath/p:<用 : 分隔的目录和 zip/jar 文件>置于勾引类路径之前‐Xdiag显示附加诊断‐Xnoclassgc禁用类垃圾网络‐Xincgc启用增量垃圾网络‐Xloggc:<file>将 GC 状态记录在文件中 (带韶光戳)‐Xbatch禁用后台编译‐Xms<size>设置初始 Java 堆大小‐Xmx<size>设置最大 Java 堆大小‐Xss<size>设置 Java 线程堆栈大小‐Xprof输出 cpu 配置文件数据‐Xfuture启用最严格的检讨, 预期将来的默认值‐Xrs减少 Java/VM 对操作系统旗子暗记的利用 (请参阅文档)‐Xcheck:jni对 JNI 函数实行其他检讨‐Xshare:off意外验测验利用共享类数据‐Xshare:auto在可能的情形下利用共享类数据 (默认)‐Xshare:on哀求利用共享类数据, 否则将失落败。‐XshowSettings显示所有设置并连续‐XshowSettings:all显示所有设置并连续‐XshowSettings:vm 显示所有与 vm 干系的设置并连续‐XshowSettings:properties显示所有属性设置并连续‐XshowSettings:locale显示所有与区域设置干系的设置并连续‐X 选项是非标准选项, 如有变动, 恕不另行关照。
2.3.1、-Xint、-Xcomp、-Xmixed
在阐明模式(interpreted mode)下,-Xint标记会逼迫JVM实行所有的字节码,当然这会降落运行速率,常日低10倍或更多。
-Xcomp参数与它(-Xint)恰好相反,JVM在第一次利用时会把所有的字节码编译成本地代码,从而带来最大程度的优化。
然而,很多运用在利用-Xcomp也会有一些性能丢失,当然这比利用-Xint丢失的少,缘故原由是-xcomp没有让JVM启用JIT编译器的全部功能。JIT编译器可以对是否须要编译做判断,如果所有代码都进行编译的话,对付一些只实行一次的代码就
没故意义了。
-Xmixed是稠浊模式,将阐明模式与编译模式进行稠浊利用,由jvm自己决定,这是jvm默认的模式,也是推举利用的模式。
示例:逼迫设置运行模式
#逼迫设置为阐明模式[root@node01 test]# java‐showversion ‐Xint TestJVM java version \"大众1.8.0_141\"大众Java(TM) SE Runtime Environment (build 1.8.0_141‐b15)Java HotSpot(TM) 64‐Bit Server VM (build 25.141‐b15, interpreted mode) itcast#逼迫设置为编译模式[root@node01 test]# java‐showversion ‐Xcomp TestJVM java version \"大众1.8.0_141\"大众Java(TM) SE Runtime Environment (build 1.8.0_141‐b15)Java HotSpot(TM) 64‐Bit Server VM (build 25.141‐b15, compiled mode)itcast#把稳:编译模式下,第一次实行会比阐明模式下实行慢一些,把稳不雅观察。#默认的稠浊模式[root@node01 test]# java‐showversion TestJVM java version \"大众1.8.0_141\公众Java(TM) SE Runtime Environment (build 1.8.0_141‐b15)Java HotSpot(TM) 64‐Bit Server VM (build 25.141‐b15, mixed mode) itcast
2.4、-XX参数
-XX参数也是非标准参数,紧张用于jvm的调优和debug操作。
-XX参数的利用有2种办法,一种是boolean类型,一种是非boolean类型: boolean类型
格式:-XX:[±]
如:-XX:+DisableExplicitGC 表示禁用手动调用gc操作,也便是说调用
System.gc()无效
非boolean类型格式:-XX:
如:-XX:NewRatio=1 表示新生代和老年代的比值
用法:
[root@node01 test]# java ‐showversion ‐XX:+DisableExplicitGC TestJVMjava version \"大众1.8.0_141\公众Java(TM) SE Runtime Environment (build 1.8.0_141‐b15)Java HotSpot(TM) 64‐Bit Server VM (build 25.141‐b15, mixed mode)itcast2.5、-Xms与-Xmx参数
Xms与-Xmx分别是设置jvm的堆内存的初始大小和最大大小。
-Xmx2048m:等价于-XX:MaxHeapSize,设置JVM最大堆内存为2048M。
-Xms512m:等价于-XX:InitialHeapSize,设置JVM初始堆内存为512M。适当的调度jvm的内存大小,可以充分利用做事器资源,让程序跑的更快。示例:[root@node01 test]# java ‐Xms512m ‐Xmx2048m TestJVM itcast
[root@node01 test]# java ‐Xms512m ‐Xmx2048m TestJVM itcast2.6、查看jvm的运行参数
有些时候我们须要查看jvm的运行参数,这个需求可能会存在2种情形:
第一,运行java命令时打印出运行参数; 第二,查看正在运行的java进程的参数; 2.6.1、运行java命令时打印参数
运行java命令时打印参数,须要添加-XX:+PrintFlagsFinal参数即可。
[root@node01 test]# java ‐XX:+PrintFlagsFinal ‐version [Global flags]uintx AdaptiveSizeDecrementScaleFactor= 4{product}uintx AdaptiveSizeMajorGCDecayTimeScale= 10{product}uintx AdaptiveSizePausePolicy= 0{product}uintx AdaptiveSizePolicyCollectionCostMargin= 50{product}uintx AdaptiveSizePolicyInitializingSteps= 20{product}uintx AdaptiveSizePolicyOutputInterval= 0{product}uintx AdaptiveSizePolicyWeight= 10{product}uintx AdaptiveSizeThroughPutPolicy= 0{product}uintx AdaptiveTimeWeight= 25{product}bool AdjustConcurrency= false{product}bool AggressiveOpts= false{product}intx AliasLevel= 3{C2 product}bool AlignVector= true{C2 product}intx AllocateInstancePrefetchLines= 1{product}intx AllocatePrefetchDistance= 256{product}intx AllocatePrefetchInstr= 0{product}…………………………略…………………………………………bool UseXmmI2D= false{C1 product}intx ValueSearchLimit= 1000{C2 product}bool VerifyMergedCPBytecodes= true{product}bool VerifySharedSpaces= false{product}intx WorkAroundNPTLTimedWaitHang= 1{product}uintx YoungGenerationSizeIncrement= 20{product}uintx YoungGenerationSizeSupplement= 80{product}uintx YoungGenerationSizeSupplementDecay= 8{product}uintx YoungPLABSize= 4096{product}bool ZeroTLAB= false{product}intx hashCode= 5{product} java version \"大众1.8.0_141\公众Java(TM) SE Runtime Environment (build 1.8.0_141‐b15)Java HotSpot(TM) 64‐Bit Server VM (build 25.141‐b15, mixed mode)
由上述的信息可以看出,参数有boolean类型和数字类型,值的操作符是=或:=,分别代 表默认值和被修正的值。
示例:
java ‐XX:+PrintFlagsFinal ‐XX:+VerifySharedSpaces ‐versionintx ValueMapInitialSize= 11{C1 product}intx ValueMapMaxLoopSize= 8{C1 product}intx ValueSearchLimit= 1000{C2 product}bool VerifyMergedCPBytecodes= true{product}bool VerifySharedSpaces:= true{product}intx WorkAroundNPTLTimedWaitHang= 1{product}uintx YoungGenerationSizeIncrement= 20{product}uintx YoungGenerationSizeSupplement= 80{product}uintx YoungGenerationSizeSupplementDecay= 8{product}uintx YoungPLABSize= 4096{product}bool ZeroTLAB= false{product}intx hashCode= 5{product} java version \"大众1.8.0_141\公众Java(TM) SE Runtime Environment (build 1.8.0_141‐b15)Java HotSpot(TM) 64‐Bit Server VM (build 25.141‐b15, mixed mode) #可以看到VerifySharedSpaces这个参数已经被修正了。
2.6.2、查看正在运行的jvm参数
如果想要查看正在运行的jvm就须要借助于jinfo命令查看。
首先,启动一个tomcat用于测试,来不雅观察下运行的jvm参数。
cd /tmp/rz 上传tar ‐xvf apache‐tomcat‐7.0.57.tar.gz cd apache‐tomcat‐7.0.57cd bin/./startup.sh
#http://192.168.40.133:8080/ 进行访问
访问成功:
#查看所有的参数,用法:jinfo ‐flags <进程id>
#通过jps 或者jps ‐l 查看java进程
[root@node01 bin]# jps 6346 Jps
6219 Bootstrap [root@node01 bin]# jps ‐l 6358 sun.tools.jps.Jps
6219 org.apache.catalina.startup.Bootstrap [root@node01 bin]#
[root@node01 bin]# jinfo ‐flags 6219 Attaching to process ID 6219, please wait... Debugger attached successfully.
Server compiler detected. JVM version is 25.141‐b15
Non‐default VM flags: ‐XX:CICompilerCount=2 ‐XX:InitialHeapSize=31457280
‐XX:MaxHeapSize=488636416 ‐XX:MaxNewSize=162529280 ‐ XX:MinHeapDeltaBytes=524288 ‐XX:NewSize=10485760 ‐XX:OldSize=20971520 ‐ XX:+UseCompressedClassPointers ‐XX:+UseCompressedOops ‐ XX:+UseFastUnorderedTimeStamps ‐XX:+UseParallelGC
Command line:‐Djava.util.logging.config.file=/tmp/apache‐tomcat‐ 7.0.57/conf/logging.properties ‐ Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager ‐ Djava.endorsed.dirs=/tmp/apache‐tomcat‐7.0.57/endorsed ‐ Dcatalina.base=/tmp/apache‐tomcat‐7.0.57 ‐Dcatalina.home=/tmp/apache‐ tomcat‐7.0.57 ‐Djava.io.tmpdir=/tmp/apache‐tomcat‐7.0.57/temp
#查看某一参数的值,用法:jinfo ‐flag <参数名> <进程id> [root@node01 bin]# jinfo ‐flag MaxHeapSize 6219
‐XX:MaxHeapSize=488636416
3、jvm的内存模型jvm的内存模型在1.7和1.8有较大的差异,虽然本套课程因此1.8为例进行讲解,但是我们 也是须要对1.7的内存模型有所理解,以是接下里,我们将先学习1.7再学习1.8的内存模 型。
3.1、jdk1.7的堆内存模型
Young 年轻区(代)
Young区被划分为三部分,Eden区和两个大小严格相同的Survivor区,个中, Survivor区间中,某一时候只有个中一个是被利用的,其余一个留做垃圾网络时复制 工具用,在Eden区间变满的时候, GC就会将存活的工具移到空闲的Survivor区间中,根据JVM的策略,在经由几次垃圾网络后,任然存活于Survivor的工具将被移动到Tenured区间。
Tenured 年迈区
Tenured区紧张保存生命周期长的工具,一样平常是一些老的工具,当一些工具在Young 复制转移一定的次数往后,工具就会被转移到Tenured区,一样平常如果系统中用了application级别的缓存,缓存中的工具每每会被转移到这一区间。
Perm 永久区
Perm代紧张保存class,method,filed工具,这部份的空间一样平常不会溢出,除非一次性 加载了很多的类,不过在涉及到热支配的运用做事器的时候,有时候会碰着java.lang.OutOfMemoryError : PermGen space 的缺点,造成这个缺点的很大缘故原由就有可能是每次都重新支配,但是重新支配后,类的class没有被卸载掉,这样就造 成了大量的class工具保存在了perm中,这种情形下,一样平常重新启动运用做事器可以 办理问题。
Virtual区:
最大内存和初始内存的差值,便是Virtual区。
3.2、jdk1.8的堆内存模型
由上图可以看出,jdk1.8的内存模型是由2部分组成,年轻代 + 年迈代。年轻代:Eden + 2Survivor
年迈代:OldGen
在jdk1.8中变革最大的Perm区,用Metaspace(元数据空间)进行了更换。
须要特殊解释的是:Metaspace所占用的内存空间不是在虚拟机内部,而是在本地内存 空间中,这也是与1.7的永久代最大的差异所在。
3.3、为什么要废弃1.7中的永久区?
官网给出理解释:http://openjdk.java.net/jeps/122
This is part of the JRockit and Hotspot convergence effort. JRockitcustomers do not need to configure the permanent generation (since JRockit does not have a permanent generation) and are accustomed to not configuring the permanent generation.移除永久代是为领悟HotSpot JVM与 JRockit VM而做出的努力,由于JRockit没有永久代,不须要配置永久代。
现实利用中,由于永久代内存常常不足用或发生内存透露,爆出非常
java.lang.OutOfMemoryError: PermGen。
基于此,将永久区废弃,而改用元空间,改为了利用本地内存空间。
3.4、通过jstat命令进行查看堆内存利用情形
jstat命令可以查看堆内存各部分的利用量,以及加载类的数量。命令的格式如下: jstat [-命令选项] [vmid] [间隔韶光/毫秒] [查询次数]
3.4.1、查看class加载统计
[root@node01 ~]# jps7080 Jps6219 Bootstrap[root@node01 ~]# jstat ‐class 6219LoadedBytesUnloadedBytesTime32737122.300.03.98
解释:
Loaded:加载class的数量
Bytes:所占用空间大小
Unloaded:未加载数量
Bytes:未加载占用空间
Time:韶光
3.4.2、查看编译统计
[root@node01 ~]# jstat ‐compiler 6219Compiled Failed InvalidTimeFailedType FailedMethod 2376108.041org/apache/tomcat/util/IntrospectionUtils setProperty
解释:
Compiled:编译数量。
Failed:失落败数量
Invalid:不可用数量
Time:韶光
FailedType:失落败类型
FailedMethod:失落败的方法
3.4.3、垃圾回收统计
[root@node01 ~]# jstat ‐gc 6219S0CS1CS0US1UECEUOCOUMCMUCCSCCCSUYGCYGCTFGCFGCTGCT9216.0 8704.00.06127.3 62976.03560.433792.020434.923808.0 23196.1 2560.0 2361.671.07810.2441.323
#也可以指定打印的间隔和次数,每1秒中打印一次,共打印5次
[root@node01 ~]# jstat ‐gc 6219 1000 5S0CS1CS0US1UECEUOCOUMC MUCCSCCCSUYGCYGCTFGCFGCTGCT9216.0 8704.00.06127.3 62976.03917.333792.020434.923808.0 23196.1 2560.0 2361.671.07810.2441.3239216.0 8704.00.06127.3 62976.03917.333792.020434.923808.0 23196.1 2560.0 2361.671.07810.2441.3239216.0 8704.00.06127.3 62976.03917.333792.020434.923808.0 23196.1 2560.0 2361.671.07810.2441.3239216.0 8704.00.06127.3 62976.03917.333792.020434.923808.0 23196.1 2560.0 2361.671.07810.2441.3239216.0 8704.00.06127.3 62976.03917.333792.020434.923808.0 23196.1 2560.0 2361.671.07810.2441.323
解释:
S0C:第一个Survivor区的大小(KB)
S1C:第二个Survivor区的大小(KB)
S0U:第一个Survivor区的利用大小(KB)
S1U:第二个Survivor区的利用大小(KB) EC:Eden区的大小(KB)
EU:Eden区的利用大小(KB)
OC:Old 区 大 小 (KB)
OU:Old 使 用 大 小 (KB)
MC:方法区大小(KB)
MU:方法区利用大小(KB)
CCSC:压缩类空间大小(KB)
CCSU:压缩类空间利用大小(KB)
YGC:年轻代垃圾回收次数
YGCT:年轻代垃圾回收花费韶光
FGC:老年代垃圾回收次数
FGCT:老年代垃圾回收花费韶光
GCT:垃圾回收花费总韶光
4、jmap的利用以及内存溢出剖析前面通过jstat可以对jvm堆的内存进行统计剖析,而jmap可以获取到更加详细的内容, 如:内存利用情形的汇总、对内存溢出的定位与剖析。
4.1、查看内存利用情形
[root@# jmap ‐heap 6219Attaching to process ID 6219, please wait... Debugger attached successfully.Server compiler detected.JVM version is 25.141‐b15using thread‐local object allocation. Parallel GC with 2 thread(s)Heap Configuration: #堆内存配置信息MinHeapFreeRatio= 0MaxHeapFreeRatio= 100MaxHeapSize= 488636416 (466.0MB)NewSize= 10485760 (10.0MB)MaxNewSize= 162529280 (155.0MB)OldSize= 20971520 (20.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 = 123731968 (118.0MB)used= 1384736 (1.320587158203125MB) free= 122347232 (116.67941284179688MB) 1.1191416594941737% usedFrom Space:capacity = 9437184 (9.0MB) used= 0 (0.0MB)free= 9437184 (9.0MB)0.0% used To Space:capacity = 9437184 (9.0MB) used= 0 (0.0MB)free= 9437184 (9.0MB)0.0% usedPS Old Generation #年迈代capacity = 28311552 (27.0MB)used = 13698672 (13.064071655273438MB) free = 14612880 (13.935928344726562MB) 48.38545057508681% used13648 interned Strings occupying 1866368 bytes.
4.2、查看内存中工具数量及大小
#查看所有工具,包括生动以及非生动的jmap ‐histo <pid> | more#查看生动工具jmap ‐histo:live <pid> | more[root@node01 ~]# jmap ‐histo:live 6219 | more num#instances#bytesclass name‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐ 1:374377914608[C2:34916837984java.lang.String3:884654848[B4:17188550016java.util.HashMap$Node5:3674424968java.lang.Class6:6322395512[Ljava.lang.Object;7:3738328944java.lang.reflect.Method8:1028208048[Ljava.util.HashMap$Node;9:2247144264[I10:4305137760java.util.concurrent.ConcurrentHashMap$Node11:1270109080[Ljava.lang.String;12:6484128[Ljava.util.concurrent.ConcurrentHashMap$Node;13:171482272java.util.HashMap14:328570072[Ljava.lang.Class;15:288869312java.util.ArrayList16:398363728java.lang.Object17:127161008org.apache.tomcat.util.digester.CallMethodRule18:151860720java.util.LinkedHashMap$Entry19:167153472com.sun.org.apache.xerces.internal.xni.QName20:8850880[Ljava.util.WeakHashMap$Entry;21:61849440java.lang.reflect.Constructor22:154549440java.util.Hashtable$Entry23:102741080java.util.TreeMap$Entry24:84640608org.apache.tomcat.util.modeler.AttributeInfo 25:14238032[S26:94637840java.lang.ref.SoftReference27:22636816[[C。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。
#工具解释
Bbyte
Cchar
Ddouble
Ffloat
Iint
Jlong
Zboolean
[数组,如[I表示int[] [L+类名 其他工具
4.3、将内存利用情形dump到文件中
有些时候我们须要将jvm当前内存中的情形dump到文件中,然后对它进行剖析,jmap也 是支持dump到文件中的。
#用法:jmap ‐dump:format=b,file=dumpFileName <pid>#示例jmap ‐dump:format=b,file=/tmp/dump.dat 6219
可以看到已经在/tmp下天生了dump.dat的文件。
4.4、通过jhat对dump文件进行剖析
在上一小节中,我们将jvm的内存dump到文件中,这个文件是一个二进制的文件,不方 便查看,这时我们可以借助于jhat工具进行查看。
#用法:
jhat ‐port <port> <file>
#示例:
[root@node01 tmp]# jhat ‐port 9999 /tmp/dump.dat Reading from /tmp/dump.dat...
Dump file created Mon Sep 10 01:04:21 CST 2018 Snapshot read, resolving...
Resolving 204094 objects...
Chasing references, expect 40 dots........................................
Eliminating duplicate references........................................
Snapshot resolved.
Started HTTP server on port 9999 Server is ready.
打开浏览器进行访问:http://192.168.40.133:9999/
在末了面有OQL查询功能。
4.5、通过MAT工具对dump文件进行剖析
4.5.1、MAT工具先容
MAT(Memory Analyzer Tool),一个基于Eclipse的内存剖析工具,是一个快速、功能丰富的JAVA heap剖析工具,它可以帮助我们查找内存泄露和减少内存花费。利用内存剖析工具从浩瀚的工具中进行剖析,快速的打算出在内存中工具的占用大小,看看是谁阻挡 了垃圾网络器的回收事情,并可以通过报表直不雅观的查看到可能造成这种结果的工具。
官网地址:https://www.eclipse.org/mat/
4.5.2、下载安装
下载地址:https://www.eclipse.org/mat/downloads.php
将下载得到的MemoryAnalyzer-1.8.0.20180604-win32.win32.x86_64.zip进行解压
4.5.3、利用
查看工具以及它的依赖:
查看可能存在内存透露的剖析:
5、实战:内存溢出的定位与剖析
内存溢出在实际的生产环境中常常会碰着,比如,不断的将数据写入到一个凑集中,涌现了去世循环,读取超大的文件等等,都可能会造成内存溢出。
如果涌现了内存溢出,首先我们须要定位到发生内存溢出的环节,并且进行剖析,是正常还是非正常情形,如果是正常的需求,就该当考虑加大内存的设置,如果是非正常需求,那么就要对代码进行修正,修复这个bug。
首先,我们得先学会如何定位问题,然后再进行剖析。如何定位问题呢,我们须要借助于jmap与MAT工具进行定位剖析。
接下来,我们仿照内存溢出的场景。
5.1、仿照内存溢出
编写代码,向List凑集中添加100万个字符串,每个字符串由1000个UUID组成。如果程 序能够正常实行,末了打印ok。
package cn.itcast.jvm;import java.util.ArrayList;import java.util.List; import java.util.UUID;public class TestJvmOutOfMemory {public static void main(String[] args) {List<Object> list = new ArrayList<>(); for (int i = 0; i < 10000000; i++) {String str = \"大众\"大众;for (int j = 0; j < 1000; j++) {str += UUID.randomUUID().toString();}list.add(str);}System.out.println(\"大众ok\公众);}}
为了演示效果,我们将设置实行的参数,这里利用的是Idea编辑器。
#参数如下:‐Xms8m ‐Xmx8m ‐XX:+HeapDumpOnOutOfMemoryError
5.2、运行测试
测试结果如下:
java.lang.OutOfMemoryError: Java heap space Dumping heap to java_pid5348.hprof ...Heap dump file created [8137186 bytes in 0.032 secs]Exception in thread \"大众main\"大众 java.lang.OutOfMemoryError: Java heap space at java.util.Arrays.copyOf(Arrays.java:3332)at java.lang.AbstractStringBuilder.ensureCapacityInternal(AbstractStringBuil der.java:124)at java.lang.AbstractStringBuilder.append(AbstractStringBuilder.java:448)at java.lang.StringBuilder.append(StringBuilder.java:136)at cn.itcast.jvm.TestJvmOutOfMemory.main(TestJvmOutOfMemory.java:14) Process finished with exit code 1
可以看到,当发生内存溢出时,会dump文件到java_pid5348.hprof。
5.3、导入到MAT工具中进行剖析
可以看到,有91.03%的内存由Object[]数组霸占,以是比较可疑。
剖析:这个可疑是精确的,由于已经有超过90%的内存都被它霸占,这是非常有可能涌现内存溢出的。
查看详情:
可以看到凑集中存储了大量的uuid字符串。
6、jstack的利用有些时候我们须要查看下jvm中的线程实行情形,比如,创造做事器的CPU的负载溘然增高了、涌现了去世锁、去世循环等,我们该如何剖析呢?
由于程序是正常运行的,没有任何的输出,从日志方面也看不出什么问题,以是就须要 看下jvm的内部线程的实行情形,然后再进行剖析查找出缘故原由。
这个时候,就须要借助于jstack命令了,jstack的浸染是将正在运行的jvm的线程情形进 行快照,并且打印出来:
#用法:jstack <pid>[root@node01 bin]# jstack 2203Full thread dump Java HotSpot(TM) 64‐Bit Server VM (25.141‐b15 mixed mode):\"大众Attach Listener\"大众 #24 daemon prio=9 os_prio=0 tid=0x00007fabb4001000 nid=0x906 waiting on condition [0x0000000000000000]java.lang.Thread.State: RUNNABLE\"大众http‐bio‐8080‐exec‐5\公众 #23 daemon prio=5 os_prio=0 tid=0x00007fabb057c000 nid=0x8e1 waiting on condition [0x00007fabd05b8000]java.lang.Thread.State: WAITING (parking) at sun.misc.Unsafe.park(Native Method)‐ parking to wait for<0x00000000f8508360> (a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject)at java.util.concurrent.locks.LockSupport.park(LockSupport.java:175) atjava.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.awa it(AbstractQueuedSynchronizer.java:2039)at java.util.concurrent.LinkedBlockingQueue.take(LinkedBlockingQueue.java:44 2)at org.apache.tomcat.util.threads.TaskQueue.take(TaskQueue.java:104) at org.apache.tomcat.util.threads.TaskQueue.take(TaskQueue.java:32) atjava.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:1 074)at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1134)at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.jav a:624)at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)at java.lang.Thread.run(Thread.java:748)\"大众http‐bio‐8080‐exec‐4\"大众 #22 daemon prio=5 os_prio=0 tid=0x00007fab9c113800nid=0x8e0 waiting on condition [0x00007fabd06b9000] java.lang.Thread.State: WAITING (parking)at sun.misc.Unsafe.park(Native Method)‐ parking to wait for<0x00000000f8508360> (a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject)at java.util.concurrent.locks.LockSupport.park(LockSupport.java:175) atjava.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.awa it(AbstractQueuedSynchronizer.java:2039)at java.util.concurrent.LinkedBlockingQueue.take(LinkedBlockingQueue.java:44 2)at org.apache.tomcat.util.threads.TaskQueue.take(TaskQueue.java:104) at org.apache.tomcat.util.threads.TaskQueue.take(TaskQueue.java:32) atjava.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:1 074)at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1134)at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.jav a:624)at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)at java.lang.Thread.run(Thread.java:748)\"大众http‐bio‐8080‐exec‐3\公众 #21 daemon prio=5 os_prio=0 tid=0x0000000001aeb800 nid=0x8df waiting on condition [0x00007fabd09ba000]java.lang.Thread.State: WAITING (parking) at sun.misc.Unsafe.park(Native Method)‐ parking to wait for<0x00000000f8508360> (a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject)at java.util.concurrent.locks.LockSupport.park(LockSupport.java:175) atjava.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.awa it(AbstractQueuedSynchronizer.java:2039)atjava.util.concurrent.LinkedBlockingQueue.take(LinkedBlockingQueue.java:44 2)at org.apache.tomcat.util.threads.TaskQueue.take(TaskQueue.java:104) at org.apache.tomcat.util.threads.TaskQueue.take(TaskQueue.java:32) atjava.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:1 074)at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1134)at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.jav a:624)at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)at java.lang.Thread.run(Thread.java:748)\公众http‐bio‐8080‐exec‐2\"大众 #20 daemon prio=5 os_prio=0 tid=0x0000000001aea000 nid=0x8de waiting on condition [0x00007fabd0abb000]java.lang.Thread.State: WAITING (parking) at sun.misc.Unsafe.park(Native Method)‐ parking to wait for<0x00000000f8508360> (a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject)at java.util.concurrent.locks.LockSupport.park(LockSupport.java:175) atjava.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.awa it(AbstractQueuedSynchronizer.java:2039)at java.util.concurrent.LinkedBlockingQueue.take(LinkedBlockingQueue.java:44 2)at org.apache.tomcat.util.threads.TaskQueue.take(TaskQueue.java:104) at org.apache.tomcat.util.threads.TaskQueue.take(TaskQueue.java:32) atjava.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:1 074)at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1134)atjava.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.jav a:624)at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)at java.lang.Thread.run(Thread.java:748)\"大众http‐bio‐8080‐exec‐1\"大众 #19 daemon prio=5 os_prio=0 tid=0x0000000001ae8800 nid=0x8dd waiting on condition [0x00007fabd0bbc000]java.lang.Thread.State: WAITING (parking) at sun.misc.Unsafe.park(Native Method)‐ parking to wait for<0x00000000f8508360> (a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject)at java.util.concurrent.locks.LockSupport.park(LockSupport.java:175) atjava.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.awa it(AbstractQueuedSynchronizer.java:2039)at java.util.concurrent.LinkedBlockingQueue.take(LinkedBlockingQueue.java:44 2)at org.apache.tomcat.util.threads.TaskQueue.take(TaskQueue.java:104) at org.apache.tomcat.util.threads.TaskQueue.take(TaskQueue.java:32) atjava.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:1 074)at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1134)at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.jav a:624)at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)at java.lang.Thread.run(Thread.java:748)\"大众ajp‐bio‐8009‐AsyncTimeout\"大众 #17 daemon prio=5 os_prio=0 tid=0x00007fabe8128000 nid=0x8d0 waiting on condition [0x00007fabd0ece000]java.lang.Thread.State: TIMED_WAITING (sleeping) at java.lang.Thread.sleep(Native Method)at org.apache.tomcat.util.net.JIoEndpoint$AsyncTimeout.run(JIoEndpoint.java: 152)at java.lang.Thread.run(Thread.java:748)\"大众ajp‐bio‐8009‐Acceptor‐0\"大众 #16 daemon prio=5 os_prio=0 tid=0x00007fabe82d4000 nid=0x8cf runnable [0x00007fabd0fcf000]java.lang.Thread.State: RUNNABLEat java.net.PlainSocketImpl.socketAccept(Native Method) atjava.net.AbstractPlainSocketImpl.accept(AbstractPlainSocketImpl.java:409) at java.net.ServerSocket.implAccept(ServerSocket.java:545)at java.net.ServerSocket.accept(ServerSocket.java:513) atorg.apache.tomcat.util.net.DefaultServerSocketFactory.acceptSocket(Defaul tServerSocketFactory.java:60)at org.apache.tomcat.util.net.JIoEndpoint$Acceptor.run(JIoEndpoint.java:220)at java.lang.Thread.run(Thread.java:748)\"大众http‐bio‐8080‐AsyncTimeout\公众 #15 daemon prio=5 os_prio=0 tid=0x00007fabe82d1800 nid=0x8ce waiting on condition [0x00007fabd10d0000]java.lang.Thread.State: TIMED_WAITING (sleeping) at java.lang.Thread.sleep(Native Method)at org.apache.tomcat.util.net.JIoEndpoint$AsyncTimeout.run(JIoEndpoint.java: 152)at java.lang.Thread.run(Thread.java:748)\"大众http‐bio‐8080‐Acceptor‐0\"大众 #14 daemon prio=5 os_prio=0 tid=0x00007fabe82d0000 nid=0x8cd runnable [0x00007fabd11d1000]java.lang.Thread.State: RUNNABLEat java.net.PlainSocketImpl.socketAccept(Native Method) atjava.net.AbstractPlainSocketImpl.accept(AbstractPlainSocketImpl.java:409) at java.net.ServerSocket.implAccept(ServerSocket.java:545)at java.net.ServerSocket.accept(ServerSocket.java:513)atorg.apache.tomcat.util.net.DefaultServerSocketFactory.acceptSocket(Defaul tServerSocketFactory.java:60)at org.apache.tomcat.util.net.JIoEndpoint$Acceptor.run(JIoEndpoint.java:220)at java.lang.Thread.run(Thread.java:748)\"大众ContainerBackgroundProcessor[StandardEngine[Catalina]]\"大众 #13 daemon prio=5 os_prio=0 tid=0x00007fabe82ce000 nid=0x8cc waiting on condition [0x00007fabd12d2000]java.lang.Thread.State: TIMED_WAITING (sleeping) at java.lang.Thread.sleep(Native Method)at org.apache.catalina.core.ContainerBase$ContainerBackgroundProcessor.run(C ontainerBase.java:1513)at java.lang.Thread.run(Thread.java:748)\"大众GC Daemon\"大众 #10 daemon prio=2 os_prio=0 tid=0x00007fabe83b4000 nid=0x8b3 in Object.wait() [0x00007fabd1c2f000]java.lang.Thread.State: TIMED_WAITING (on object monitor) at java.lang.Object.wait(Native Method)‐waiting on <0x00000000e315c2d0> (a sun.misc.GC$LatencyLock) at sun.misc.GC$Daemon.run(GC.java:117)‐locked <0x00000000e315c2d0> (a sun.misc.GC$LatencyLock)\公众Service Thread\"大众 #7 daemon prio=9 os_prio=0 tid=0x00007fabe80c3800 nid=0x8a5 runnable [0x0000000000000000]java.lang.Thread.State: RUNNABLE\公众C1 CompilerThread1\"大众 #6 daemon prio=9 os_prio=0 tid=0x00007fabe80b6800 nid=0x8a4 waiting on condition [0x0000000000000000]java.lang.Thread.State: RUNNABLE\"大众C2 CompilerThread0\"大众 #5 daemon prio=9 os_prio=0 tid=0x00007fabe80b3800 nid=0x8a3 waiting on condition [0x0000000000000000]java.lang.Thread.State: RUNNABLE\公众Signal Dispatcher\公众 #4 daemon prio=9 os_prio=0 tid=0x00007fabe80b2000 nid=0x8a2 runnable [0x0000000000000000]java.lang.Thread.State: RUNNABLE\"大众Finalizer\公众 #3 daemon prio=8 os_prio=0 tid=0x00007fabe807f000 nid=0x8a1in Object.wait() [0x00007fabd2a67000] java.lang.Thread.State: WAITING (on object monitor) at java.lang.Object.wait(Native Method)‐ waiting on <0x00000000e3162918> (a java.lang.ref.ReferenceQueue$Lock)at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:143)‐ locked <0x00000000e3162918> (a java.lang.ref.ReferenceQueue$Lock) at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:164)at java.lang.ref.Finalizer$FinalizerThread.run(Finalizer.java:209)\公众Reference Handler\"大众 #2 daemon prio=10 os_prio=0 tid=0x00007fabe807a800 nid=0x8a0 in Object.wait() [0x00007fabd2b68000]java.lang.Thread.State: WAITING (on object monitor) at java.lang.Object.wait(Native Method)‐waiting on <0x00000000e3162958> (a java.lang.ref.Reference$Lock) at java.lang.Object.wait(Object.java:502)at java.lang.ref.Reference.tryHandlePending(Reference.java:191)‐locked <0x00000000e3162958> (a java.lang.ref.Reference$Lock)at java.lang.ref.Reference$ReferenceHandler.run(Reference.java:153)\"大众main\"大众 #1 prio=5 os_prio=0 tid=0x00007fabe8009000 nid=0x89c runnable [0x00007fabed210000]java.lang.Thread.State: RUNNABLEat java.net.PlainSocketImpl.socketAccept(Native Method) atjava.net.AbstractPlainSocketImpl.accept(AbstractPlainSocketImpl.java:409) at java.net.ServerSocket.implAccept(ServerSocket.java:545)at java.net.ServerSocket.accept(ServerSocket.java:513) atorg.apache.catalina.core.StandardServer.await(StandardServer.java:453) at org.apache.catalina.startup.Catalina.await(Catalina.java:777) at org.apache.catalina.startup.Catalina.start(Catalina.java:723) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorI mpl.java:43)at java.lang.reflect.Method.invoke(Method.java:498)at org.apache.catalina.startup.Bootstrap.start(Bootstrap.java:321)at org.apache.catalina.startup.Bootstrap.main(Bootstrap.java:455)\"大众VM Thread\"大众 os_prio=0 tid=0x00007fabe8073000 nid=0x89f runnable\"大众GC task thread#0 (ParallelGC)\"大众 os_prio=0 tid=0x00007fabe801e000nid=0x89d runnable\公众GC task thread#1 (ParallelGC)\"大众 os_prio=0 tid=0x00007fabe8020000nid=0x89e runnable\公众VM Periodic Task Thread\"大众 os_prio=0 tid=0x00007fabe80d6800 nid=0x8a6waiting on conditionJNI global references: 43
6.1、线程的状态
在Java中线程的状态一共被分成6种:
初始态(NEW)
创建一个Thread工具,但还未调用start()启动线程时,线程处于初始态。 运行态(RUNNABLE),在Java中,运行态包括 就绪态 和 运行态。
就绪态
该状态下的线程已经得到实行所需的所有资源,只要CPU分配实行权就能运行。
所有就绪态的线程存放在就绪行列步队中。
运行态
得到CPU实行权,正在实行的线程。
由于一个CPU同一时候只能实行一条线程,因此每个CPU每个时候只有一条
运行态的线程。壅塞态(BLOCKED)
当一条正在实行的线程要求某一资源失落败时,就会进入壅塞态。
而在Java中,壅塞态专指要求锁失落败时进入的状态。由一个壅塞行列步队存放所有壅塞态的线程。
处于壅塞态的线程会不断要求资源,一旦要求成功,就会进入就绪行列步队,等待实行。
等待态(WAITING)
当前哨程中调用wait、join、park函数时,当前哨程就会进入等待态。 也有一个等待行列步队存放所有等待态的线程。
线程处于等待态表示它须要等待其他线程的指示才能连续运行。进入等待态的线程会开释CPU实行权,并开释资源(如:锁)
超时等待态(TIMED_WAITING)
当运行中的线程调用sleep(time)、wait、join、parkNanos、parkUntil时,就会进入该状态;
它和等待态一样,并不是由于要求不到资源,而是主动进入,并且进入后须要其他线程唤醒;
进入该状态后开释CPU实行权 和 霸占的资源。
与等待态的差异:到了超时时间后自动进入壅塞行列步队,开始竞争锁。
终止态(TERMINATED)
线程实行结束后的状态。
6.2、实战:去世锁问题
如果在生产环境发生了去世锁,我们将看到的是支配的程序没有任何反应了,这个时候我 们可以借助jstack进行剖析,下面我们实战下查找去世锁的缘故原由。
6.2.1、布局去世锁
编写代码,启动2个线程,Thread1拿到了obj1锁,准备去拿obj2锁时,obj2已经被
Thread2锁定,以是发送了去世锁。
public class TestDeadLock {private static Object obj1 = new Object(); private static Object obj2 = new Object();public static void main(String[] args) { new Thread(new Thread1()).start(); new Thread(new Thread2()).start();}private static class Thread1 implements Runnable{ @Overridepublic void run() { synchronized (obj1){System.out.println(\"大众Thread1 拿到了 obj1 的锁!
\公众);try {// 停顿2秒的意义在于,让Thread2线程拿到obj2的锁Thread.sleep(2000);} catch (InterruptedException e) { e.printStackTrace();}synchronized (obj2){System.out.println(\"大众Thread1 拿到了 obj2 的锁!
\"大众);}}}}private static class Thread2 implements Runnable{ @Overridepublic void run() { synchronized (obj2){System.out.println(\"大众Thread2 拿到了 obj2 的锁!
\"大众);try {// 停顿2秒的意义在于,让Thread1线程拿到obj1的锁Thread.sleep(2000);} catch (InterruptedException e) { e.printStackTrace();}synchronized (obj1){System.out.println(\公众Thread2 拿到了 obj1 的锁!
\"大众);}}}}}
6.2.2、在linux上运行
[root@node01 test]# javac TestDeadLock.java[root@node01 test]# ll总用量 28‐rw‐r‐‐r‐‐.1rootroot184 9月1110:39TestDeadLock$1.class‐rw‐r‐‐r‐‐.1rootroot843 9月1110:39TestDeadLock.class‐rw‐r‐‐r‐‐.1rootroot1567 9月1110:39TestDeadLock.java‐rw‐r‐‐r‐‐.1rootroot1078 9月1110:39TestDeadLock$Thread1.class‐rw‐r‐‐r‐‐.1rootroot1078 9月1110:39TestDeadLock$Thread2.class‐rw‐r‐‐r‐‐.1rootroot573 9月910:21TestJVM.class‐rw‐r‐‐r‐‐.1rootroot261 9月910:21TestJVM.java
[root@node01 test]# java TestDeadLock
Thread1 拿到了 obj1 的锁!
Thread2 拿到了 obj2 的锁!
#这里发生了去世锁,程序一贯将等待下去
6.2.3、利用jstack进行剖析
[root@node01 ~]# jstack 3256Full thread dump Java HotSpot(TM) 64‐Bit Server VM (25.141‐b15 mixed mode):\"大众Attach Listener\公众 #11 daemon prio=9 os_prio=0 tid=0x00007f5bfc001000 nid=0xcff waiting on condition [0x0000000000000000]java.lang.Thread.State: RUNNABLE\公众DestroyJavaVM\"大众 #10 prio=5 os_prio=0 tid=0x00007f5c2c008800 nid=0xcb9 waiting on condition [0x0000000000000000]java.lang.Thread.State: RUNNABLE\"大众Thread‐1\"大众 #9 prio=5 os_prio=0 tid=0x00007f5c2c0e9000 nid=0xcc5 waiting for monitor entry [0x00007f5c1c7f6000]java.lang.Thread.State: BLOCKED (on object monitor) at TestDeadLock$Thread2.run(TestDeadLock.java:47)‐waiting to lock <0x00000000f655dc40> (a java.lang.Object)‐locked <0x00000000f655dc50> (a java.lang.Object) at java.lang.Thread.run(Thread.java:748)\公众Thread‐0\公众 #8 prio=5 os_prio=0 tid=0x00007f5c2c0e7000 nid=0xcc4 waiting for monitor entry [0x00007f5c1c8f7000]java.lang.Thread.State: BLOCKED (on object monitor) at TestDeadLock$Thread1.run(TestDeadLock.java:27)‐waiting to lock <0x00000000f655dc50> (a java.lang.Object)‐locked <0x00000000f655dc40> (a java.lang.Object) at java.lang.Thread.run(Thread.java:748)\公众Service Thread\"大众 #7 daemon prio=9 os_prio=0 tid=0x00007f5c2c0d3000 nid=0xcc2 runnable [0x0000000000000000]java.lang.Thread.State: RUNNABLE\公众C1 CompilerThread1\"大众 #6 daemon prio=9 os_prio=0 tid=0x00007f5c2c0b6000 nid=0xcc1 waiting on condition [0x0000000000000000]java.lang.Thread.State: RUNNABLE\"大众C2 CompilerThread0\公众 #5 daemon prio=9 os_prio=0 tid=0x00007f5c2c0b3000 nid=0xcc0 waiting on condition [0x0000000000000000]java.lang.Thread.State: RUNNABLE\公众Signal Dispatcher\"大众 #4 daemon prio=9 os_prio=0 tid=0x00007f5c2c0b1800 nid=0xcbf runnable [0x0000000000000000]java.lang.Thread.State: RUNNABLE\"大众Finalizer\"大众 #3 daemon prio=8 os_prio=0 tid=0x00007f5c2c07e800 nid=0xcbe in Object.wait() [0x00007f5c1cdfc000]java.lang.Thread.State: WAITING (on object monitor) at java.lang.Object.wait(Native Method)‐ waiting on <0x00000000f6508ec8> (a java.lang.ref.ReferenceQueue$Lock)at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:143)‐ locked <0x00000000f6508ec8> (a java.lang.ref.ReferenceQueue$Lock) at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:164)at java.lang.ref.Finalizer$FinalizerThread.run(Finalizer.java:209)\"大众Reference Handler\公众 #2 daemon prio=10 os_prio=0 tid=0x00007f5c2c07a000 nid=0xcbd in Object.wait() [0x00007f5c1cefd000]java.lang.Thread.State: WAITING (on object monitor) at java.lang.Object.wait(Native Method)‐waiting on <0x00000000f6506b68> (a java.lang.ref.Reference$Lock) at java.lang.Object.wait(Object.java:502)at java.lang.ref.Reference.tryHandlePending(Reference.java:191)‐locked <0x00000000f6506b68> (a java.lang.ref.Reference$Lock)at java.lang.ref.Reference$ReferenceHandler.run(Reference.java:153) \"大众VM Thread\"大众 os_prio=0 tid=0x00007f5c2c072800 nid=0xcbc runnable\"大众GC task thread#0 (ParallelGC)\"大众 os_prio=0 tid=0x00007f5c2c01d800 nid=0xcba runnable\"大众GC task thread#1 (ParallelGC)\公众 os_prio=0 tid=0x00007f5c2c01f800 nid=0xcbb runnable\公众VM Periodic Task Thread\公众 os_prio=0 tid=0x00007f5c2c0d6800 nid=0xcc3 waiting on conditionJNI global references: 6Found one Java‐level deadlock:=============================\"大众Thread‐1\"大众:waiting to lock monitor 0x00007f5c080062c8 (object 0x00000000f655dc40, a java.lang.Object),which is held by \"大众Thread‐0\"大众 \"大众Thread‐0\公众:waiting to lock monitor 0x00007f5c08004e28 (object 0x00000000f655dc50, a java.lang.Object),which is held by \"大众Thread‐1\"大众Java stack information for the threads listed above:===================================================\"大众Thread‐1\"大众:at TestDeadLock$Thread2.run(TestDeadLock.java:47)‐waiting to lock <0x00000000f655dc40> (a java.lang.Object)‐locked <0x00000000f655dc50> (a java.lang.Object) at java.lang.Thread.run(Thread.java:748)\"大众Thread‐0\"大众:at TestDeadLock$Thread1.run(TestDeadLock.java:27)‐waiting to lock <0x00000000f655dc50> (a java.lang.Object)‐locked <0x00000000f655dc40> (a java.lang.Object) at java.lang.Thread.run(Thread.java:748)Found 1 deadlock.
在输出的信息中,已经看到,创造了1个去世锁,关键看这个:
\"大众Thread‐1\"大众:at TestDeadLock$Thread2.run(TestDeadLock.java:47)‐waiting to lock <0x00000000f655dc40> (a java.lang.Object)‐locked <0x00000000f655dc50> (a java.lang.Object) at java.lang.Thread.run(Thread.java:748)\"大众Thread‐0\公众:at TestDeadLock$Thread1.run(TestDeadLock.java:27)‐waiting to lock <0x00000000f655dc50> (a java.lang.Object)‐locked <0x00000000f655dc40> (a java.lang.Object) at java.lang.Thread.run(Thread.java:748)
可以清晰的看到:
Thread2获取了 <0x00000000f655dc50> 的锁,等待获取 <0x00000000f655dc40>
这个锁
Thread1获取了 <0x00000000f655dc40> 的锁,等待获取 <0x00000000f655dc50>
这个锁
由此可见,发生了去世锁
7、VisualVM工具的利用VisualVM,能够监控线程,内存情形,查看方法的CPU韶光和内存中的对 象,已被GC的工具,反向查看分配的堆栈(如100个String工具分别由哪几个工具分配出来的)。
VisualVM利用大略,险些0配置,功能还是比较丰富的,险些席卷了其它JDK自带命令的所有功能。
内存信息线程信息
Dump堆(本地进程)
Dump线程(本地进程)
打开堆Dump。堆Dump可以用jmap来天生。打开线程Dump
天生运用快照(包含内存信息、线程信息等等)
性能剖析。CPU剖析(各个方法调用韶光,检讨哪些方法耗时多),内存剖析(各种工具占用的内存,检讨哪些类占用内存多)
……
7.1、启动
在jdk的安装目录的bin目录下,找到jvisualvm.exe,双击打开即可。
7.2、查看本地进程
7.3、查看CPU、内存、类、线程运行信息
7.4、查看线程详情
也可以点击右上角Dump按钮,将线程的信息导出,实在便是实行的jstack命令。
创造,显示的内容是一样的。
7.5、抽样器
抽样器可以对CPU、内存在一段韶光内进行抽样,以供剖析。
7.6、监控远程的jvm
VisualJVM不仅是可以监控本地jvm进程,还可以监控远程的jvm进程,须要借助于JMX技能实现。
7.6.1、什么是JMX?
JMX(Java Management Extensions,即Java管理扩展)是一个为运用程序、设备、系统等植入管理功能的框架。JMX可以超过一系列异构操作系统平台、系统体系构造和网络传输协议,灵巧的开拓无缝集成的系统、网络和做事管理运用。
7.6.2、监控远程的tomcat
想要监控远程的tomcat,就须要在远程的tomcat进行对JMX配置,方法如下:
#在tomcat的bin目录下,修正catalina.sh,添加如下的参数JAVA_OPTS=\"大众‐Dcom.sun.management.jmxremote ‐Dcom.sun.management.jmxremote.port=9999 ‐ Dcom.sun.management.jmxremote.authenticate=false ‐ Dcom.sun.management.jmxremote.ssl=false\"大众#这几个参数的意思是:#‐Dcom.sun.management.jmxremote :许可利用JMX远程管理#‐Dcom.sun.management.jmxremote.port=9999 :JMX远程连接端口#‐Dcom.sun.management.jmxremote.authenticate=false :不进行身份认证,任何用户都可以连接#‐Dcom.sun.management.jmxremote.ssl=false :不该用ssl
保存退出,重启tomcat。
7.6.3、利用VisualJVM连接远程tomcat
添加远程主机:
在一个主机下可能会有很多的jvm须要监控,以是接下来要在该主机上添加须要监控的
jvm:
连接成功。利用方法和前面就一样了,就可以和监控本地jvm进程一样,监控远程的
tomcat进程。