资讯详情

JVM优化-1

JVM优化 - 第一天 今日内容 了解我们为什么要学习JVM优化 掌握jvm的运行参数以及参数的设置 掌握jvm的内存模型(堆内存) 掌握jamp使用和通过命令MAT分析工具 掌握定位分析内存溢出的方法 掌握jstack命令的使用 掌握VisualJVM工具的使用 为什么我们要对?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 -version java version “1.8.0_141” Java? SE Runtime Environment (build 1.8.0_141-b15) Java HotSpot? 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 TestJVM java version “1.8.0_141” Java? SE Runtime Environment (build 1.8.0_141-b15) Java HotSpot? 64-Bit Server VM (build 25.141-b15, mixed mode)

itcast

[root@node01 test]# java -server -showversion TestJVM java version “1.8.0_141” Java? SE Runtime Environment (build 1.8.0_141-b15) Java HotSpot? 64-Bit Server VM (build 25.141-b15, mixed mode)

itcast

#由于机器是64位系统,不支持client模式 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: 将 GC 在文件中记录状态 (带时间戳) -Xbatch 后台编译禁止 -Xms 设置初始 Java 堆大小 -Xmx 设置大 Java 堆大小 -Xss 设置 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™ SE Runtime Environment (build 1.8.0_141-b15) Java HotSpot™ 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™ SE Runtime Environment (build 1.8.0_141-b15) Java HotSpot™ 64-Bit Server VM (build 25.141-b15, compiled mode)

itcast #注意:编译模式下,第一次执行会比解释模式下执行慢一些,注意观察。

#默认的混合模式 [root@node01 test]# java -showversion TestJVM java version “1.8.0_141” Java™ SE Runtime Environment (build 1.8.0_141-b15) Java HotSpot™ 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 TestJVM java version “1.8.0_141” Java™ SE Runtime Environment (build 1.8.0_141-b15) Java HotSpot™ 64-Bit Server VM (build 25.141-b15, mixed mode)

itcast 2.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 2.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 {ARCH product} bool UseXmmI2F = false {ARCH product} bool UseXmmLoadAndClearUpper = true {ARCH product} bool UseXmmRegToRegMoveAll = true {ARCH product} bool VMThreadHintNoPreempt = false {product} intx VMThreadPriority = -1 {product} intx VMThreadStackSize = 1024 {pd product} intx ValueMapInitialSize = 11 {C1 product} intx ValueMapMaxLoopSize = 8 {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™ SE Runtime Environment (build 1.8.0_141-b15) Java HotSpot™ 64-Bit Server VM (build 25.141-b15, mixed mode) 由上述的信息可以看出,参数有boolean类型和数字类型,值的操作符是=或:=,分别代表默认值和被修改的值。 示例: java -XX:+PrintFlagsFinal -XX:+VerifySharedSpaces -version

 intx 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.57 cd 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-tomcat7.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/apachetomcat-7.0.57 -Dcatalina.home=/tmp/apache-tomcat-7.0.57 -Djava.io.tmpdir=/tmp/apachetomcat-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 + 2*Survivor 年老代: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. JRockit customers 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 ~]# jps 7080 Jps 6219 Bootstrap

[root@node01 ~]# jstat -class 6219 Loaded Bytes Unloaded Bytes Time 3273 7122.3 0 0.0 3.98 说明: Loaded:加载class的数量 Bytes:所占用空间大小 Unloaded:未加载数量 Bytes:未加载占用空间 Time:时间 3.4.2、查看编译统计 [root@node01 ~]# jstat -compiler 6219 Compiled Failed Invalid Time FailedType FailedMethod 2376 1 0 8.04 1 org/apache/tomcat/util/IntrospectionUtils setProperty 说明: Compiled:编译数量。 Failed:失败数量 Invalid:不可用数量 Time:时间 FailedType:失败类型 FailedMethod:失败的方法 3.4.3、垃圾回收统计 [root@node01 ~]# jstat -gc 6219 S0C S1C S0U S1U EC EU OC OU MC MU CCSC CCSU YGC YGCT FGC FGCT GCT 9216.0 8704.0 0.0 6127.3 62976.0 3560.4 33792.0 20434.9 23808.0 23196.1 2560.0 2361.6 7 1.078 1 0.244 1.323

#也可以指定打印的间隔和次数,每1秒中打印一次,共打印5次 [root@node01 ~]# jstat -gc 6219 1000 5 S0C S1C S0U S1U EC EU OC OU MC MU CCSC CCSU YGC YGCT FGC FGCT GCT 9216.0 8704.0 0.0 6127.3 62976.0 3917.3 33792.0 20434.9 23808.0 23196.1 2560.0 2361.6 7 1.078 1 0.244 1.323 9216.0 8704.0 0.0 6127.3 62976.0 3917.3 33792.0 20434.9 23808.0 23196.1 2560.0 2361.6 7 1.078 1 0.244 1.323 9216.0 8704.0 0.0 6127.3 62976.0 3917.3 33792.0 20434.9 23808.0 23196.1 2560.0 2361.6 7 1.078 1 0.244 1.323 9216.0 8704.0 0.0 6127.3 62976.0 3917.3 33792.0 20434.9 23808.0 23196.1 2560.0 2361.6 7 1.078 1 0.244 1.323 9216.0 8704.0 0.0 6127.3 62976.0 3917.3 33792.0 20434.9 23808.0 23196.1 2560.0 2361.6 7 1.078 1 0.244 1.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@node01 ~]# jmap -heap 6219 Attaching to process ID 6219, please wait… Debugger attached successfully. Server compiler detected. JVM version is 25.141-b15

using thread-local object allocation. Parallel GC with 2 thread(s)

Heap Configuration: #堆内存配置信息 MinHeapFreeRatio = 0 MaxHeapFreeRatio = 100 MaxHeapSize = 488636416 (466.0MB) NewSize = 10485760 (10.0MB) MaxNewSize = 162529280 (155.0MB) OldSize = 20971520 (20.0MB) NewRatio = 2 SurvivorRatio = 8 MetaspaceSize = 21807104 (20.796875MB) CompressedClassSpaceSize = 1073741824 (1024.0MB) MaxMetaspaceSize = 17592186044415 MB G1HeapRegionSize = 0 (0.0MB)

Heap Usage: # 堆内存的使用情况 PS Young Generation #年轻代 Eden Space: capacity = 123731968 (118.0MB) used = 1384736 (1.320587158203125MB) free = 122347232 (116.67941284179688MB) 1.1191416594941737% used From 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% used PS Old Generation #年老代 capacity = 28311552 (27.0MB) used = 13698672 (13.064071655273438MB) free = 14612880 (13.935928344726562MB) 48.38545057508681% used

13648 interned Strings occupying 1866368 bytes. 4.2、查看内存中对象数量及大小 #查看所有对象,包括活跃以及非活跃的 jmap -histo | more

#查看活跃对象 jmap -histo:live | more

[root@node01 ~]# jmap -histo:live 6219 | more

num #instances #bytes class name ---------------------------------------------- 1: 37437 7914608 [C 2: 34916 837984 java.lang.String 3: 884 654848 [B 4: 17188 550016 java.util.HashMap N o d e 5 : 3674424968 j a v a . l a n g . C l a s s 6 : 6322395512 [ L j a v a . l a n g . O b j e c t ; 7 : 3738328944 j a v a . l a n g . r e f l e c t . M e t h o d 8 : 1028208048 [ L j a v a . u t i l . H a s h M a p Node 5: 3674 424968 java.lang.Class 6: 6322 395512 [Ljava.lang.Object; 7: 3738 328944 java.lang.reflect.Method 8: 1028 208048 [Ljava.util.HashMap Node5:3674424968java.lang.Class6:6322395512[Ljava.lang.Object;7:3738328944java.lang.reflect.Method8:1028208048[Ljava.util.HashMapNode; 9: 2247 144264 [I 10: 4305 137760 java.util.concurrent.ConcurrentHashMap N o d e 11 : 1270109080 [ L j a v a . l a n g . S t r i n g ; 12 : 6484128 [ L j a v a . u t i l . c o n c u r r e n t . C o n c u r r e n t H a s h M a p Node 11: 1270 109080 [Ljava.lang.String; 12: 64 84128 [Ljava.util.concurrent.ConcurrentHashMap Node11:1270109080[Ljava.lang.String;12:6484128[Ljava.util.concurrent.ConcurrentHashMapNode; 13: 1714 82272 java.util.HashMap 14: 3285 70072 [Ljava.lang.Class; 15: 2888 69312 java.util.ArrayList 16: 3983 63728 java.lang.Object 17: 1271 61008 org.apache.tomcat.util.digester.CallMethodRule 18: 1518 60720 java.util.LinkedHashMap E n t r y 19 : 167153472 c o m . s u n . o r g . a p a c h e . x e r c e s . i n t e r n a l . x n i . Q N a m e 20 : 8850880 [ L j a v a . u t i l . W e a k H a s h M a p Entry 19: 1671 53472 com.sun.org.apache.xerces.internal.xni.QName 20: 88 50880 [Ljava.util.WeakHashMap Entry19:167153472com.sun.org.apache.xerces.internal.xni.QName20:8850880[Ljava.util.WeakHashMapEntry; 21: 618 49440 java.lang.reflect.Constructor 22: 1545 49440 java.util.Hashtable E n t r y 23 : 102741080 j a v a . u t i l . T r e e M a p Entry 23: 1027 41080 java.util.TreeMap Entry23:102741080java.util.TreeMapEntry 24: 846 40608 org.apache.tomcat.util.modeler.AttributeInfo 25: 142 38032 [S 26: 946 37840 java.lang.ref.SoftReference 27: 226 36816 [[C 。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。 #对象说明 B byte C char D double F float I int J long Z boolean [ 数组,如[I表示int[] [L+类名 其他对象 4.3、将内存使用情况dump到文件中 有些时候我们需要将jvm当前内存中的情况dump到文件中,然后对它进行分析,jmap也是支持dump到文件中 的。 #用法: jmap -dump:format=b,file=dumpFileName

#示例 jmap -dump:format=b,file=/tmp/dump.dat 6219

可以看到已经在/tmp下生成了dump.dat的文件。 4.4、通过jhat对dump文件进行分析 在上一小节中,我们将jvm的内存dump到文件中,这个文件是一个二进制的文件,不方便查看,这时我们可以借 助于jhat工具进行查看。 #用法: jhat -port

#示例: [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(AbstractStringBuilder.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

[root@node01 bin]# jstack 2203 Full thread dump Java HotSpot™ 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 C o n d i t i o n O b j e c t ) a t j a v a . u t i l . c o n c u r r e n t . l o c k s . L o c k S u p p o r t . p a r k ( L o c k S u p p o r t . j a v a : 175 ) a t j a v a . u t i l . c o n c u r r e n t . l o c k s . A b s t r a c t Q u e u e d S y n c h r o n i z e r ConditionObject) at java.util.concurrent.locks.LockSupport.park(LockSupport.java:175) at java.util.concurrent.locks.AbstractQueuedSynchronizer ConditionObject)atjava.util.concurrent.locks.LockSupport.park(LockSupport.java:175)atjava.util.concurrent.locks.AbstractQueuedSynchronizerConditionObject.await(AbstractQueue dSynchronizer.java:2039) at java.util.concurrent.LinkedBlockingQueue.take(LinkedBlockingQueue.java:442) at org.apache.tomcat.util.threads.TaskQueue.take(TaskQueue.java:104) at org.apache.tomcat.util.threads.TaskQueue.take(TaskQueue.java:32) at java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:1074) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1134) at java.util.concurrent.ThreadPoolExecutor W o r k e r . r u n ( T h r e a d P o o l E x e c u t o r . j a v a : 624 ) a t o r g . a p a c h e . t o m c a t . u t i l . t h r e a d s . T a s k T h r e a d Worker.run(ThreadPoolExecutor.java:624) at org.apache.tomcat.util.threads.TaskThread Worker.run(ThreadPoolExecutor.java:624)atorg.apache.tomcat.util.threads.TaskThreadWrappingRunnable.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=0x00007fab9c113800 nid=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 C o n d i t i o n O b j e c t ) a t j a v a . u t i l . c o n c u r r e n t . l o c k s . L o c k S u p p o r t . p a r k ( L o c k S u p p o r t . j a v a : 175 ) a t j a v a . u t i l . c o n c u r r e n t . l o c k s . A b s t r a c t Q u e u e d S y n c h r o n i z e r ConditionObject) at java.util.concurrent.locks.LockSupport.park(LockSupport.java:175) at java.util.concurrent.locks.AbstractQueuedSynchronizer ConditionObject)atjava.util.concurrent.locks.LockSupport.park(LockSupport.java:175)atjava<

标签: 3917连接器

锐单商城拥有海量元器件数据手册IC替代型号,打造 电子元器件IC百科大全!

锐单商城 - 一站式电子元器件采购平台