新手做网站如何赚钱,网站建设军成,wordpress 文章空白,中国建设银行有哪些招聘网站Java系列笔记(4) - JVM监控与调优【转】 目录 参数设置收集器搭配启动内存分配监控工具和方法调优方法调优实例 光说不练假把式#xff0c;学习Java GC机制的目的是为了实用#xff0c;也就是为了在JVM出现问题时分析原因并解决之。通过学习#xff0c;我觉得JVM监控与调…Java系列笔记(4) - JVM监控与调优【转】 目录 参数设置收集器搭配启动内存分配监控工具和方法调优方法调优实例 光说不练假把式学习Java GC机制的目的是为了实用也就是为了在JVM出现问题时分析原因并解决之。通过学习我觉得JVM监控与调优主要的着眼点在于如何配置、如何监控、如何优化3点上。下面就将针对这3点进行学习。 如果您对Java的内存区域划分和内存回收机制尚不明确那在阅读本文前请先阅读我的前一篇博客《Java系列笔记(3) - Java 内存区域和GC机制》在该博客中详细叙述了Java HotSpot虚拟机Sun/Oracle JDK系列默认的虚拟机的内存分配和垃圾回收机制。本文很多内容将依据上一篇博客同时本文所针对的虚拟机也是HotSpot虚拟机。参数设置 在Java虚拟机的参数中有3种表示方法出自http://www.cnblogs.com/wenfeng762/archive/2011/08/14/2137810.html用“ps -ef |grep java命令可以得到当前Java进程的所有启动参数和配置参数 标准参数-所有的JVM实现都必须实现这些参数的功能而且向后兼容非标准参数-X默认jvm实现这些参数的功能但是并不保证所有jvm实现都满足且不保证向后兼容非Stable参数-XX此类参数各个jvm实现会有所不同将来可能会随时取消需要慎重使用但是这些参数往往是非常有用的额外的-DpropertyName“value”的形式定义了一些全局属性值下面有介绍。本文只重点介绍一些重要和常用的参数如果想了解全部参数可以参考下面的文章 《Java HotSpot VM Options》 《Java 6 JVM参数选项大全中文版》上面一篇的中文版 《JVM启动参数大全》 标准参数 其实标准参数是用过Java的人都最熟悉的就是你在运行java命令时后面加上的参数如java -version, java -jar 等输入命令java -help或java -?就能获得当前机器所有java的标准参数列表。-client设置jvm使用client模式这是一般在pc机器上使用的模式启动很快但性能和内存管理效率并不高多用于桌面应用-server使用server模式启动速度虽然慢比client模式慢10%左右但是性能和内存管理效率很高适用于服务器用于生成环境、开发环境或测试环境的服务端如果没有指定-server或-clientJVM启动的时候会自动检测当前主机是否为服务器如果是就以server模式启动64位的JVM只有server模式所以无法使用-client参数默认情况下不同的启动模式执行GC的方式有所区别 启动模式新生代GC方式旧生代和持久代GC的方式client串行串行server并行并发如果没有指定-server或-client模式则判断方法如下-classpath / -cpJVM加载和搜索文件的目录路径多个路径用;分隔。注意如果使用了-classpathJVM就不会再搜索环境变量中定义的CLASSPATH路径。JVM搜索路径的顺序为1先搜索JVM自带的jar或zip包Bootstrat搜索路径可以用System.getProperty(sun.boot.class.path)获得2搜索JRE_HOME/lib/ext下的jar包Extension搜索路径可以用System.getProperty(java.ext.dirs)获得3搜索用户自定义目录顺序为当前目录.CLASSPATH-cp搜索路径用System.getProperty(java.class.path)获得-DpropertyNamevalue定义系统的全局属性值如配置文件地址等如果value有空格可以用-Dnamespace string这样的形式来定义用System.getProperty(propertyName)可以获得这些定义的属性值在代码中也可以用System.setProperty(propertyName,value)的形式来定义属性。-verbose 这是查询GC问题最常用的命令之一具体参数如-verbose:class 输出jvm载入类的相关信息当jvm报告说找不到类或者类冲突时可此进行诊断。-verbose:gc 输出每次GC的相关情况后面会有更详细的介绍。-verbose:jni 输出native方法调用的相关情况一般用于诊断jni调用错误信息。非标准参数非标准参数是在标准参数的基础上进行扩展的参数输入“java -X”命令能够获得当前JVM支持的所有非标准参数列表你会发现其实并不多哦。 在不同类型的JVM中采用的参数有所不同在讲解非标准参数时请参考下面的图对内存区域的大小有个形象的了解下图出自http://iamzhongyong.iteye.com/blog/1333100 -Xmn新生代内存大小的最大值包括E区和两个S区的总和使用方法如-Xmn65535-Xmn1024k-Xmn512m-Xmn1g (-Xms,-Xmx也是种写法)-Xmn只能使用在JDK1.4或之后的版本中之前的1.3/1.4版本中可使用-XX:NewSize设置年轻代大小用-XX:MaxNewSize设置年轻代最大值如果同时设置了-Xmn和-XX:NewSize-XX:MaxNewSize则谁设置在后面谁就生效如果同时设置了-XX:NewSize -XX:MaxNewSize与-XX:NewRatio则实际生效的值是min(MaxNewSize,max(NewSize, heap/(NewRatio1)))看考http://www.open-open.com/home/space.php?uid71669doblogid8891在开发、测试环境可以-XX:NewSize 和 -XX:MaxNewSize来设置新生代大小但在线上生产环境使用-Xmn一个即可推荐或者将-XX:NewSize 和 -XX:MaxNewSize设置为同一个值这样能够防止在每次GC之后都要调整堆的大小即抖动抖动会严重影响性能 -Xms初始堆的大小也是堆大小的最小值默认值是总共的物理内存/64且小于1G默认情况下当堆中可用内存小于40%(这个值可以用-XX: MinHeapFreeRatio 调整如-X:MinHeapFreeRatio30)时堆内存会开始增加一直增加到-Xmx的大小 -Xmx堆的最大值默认值是总共的物理内存/64且小于1G如果Xms和Xmx都不设置则两者大小会相同默认情况下当堆中可用内存大于70%这个值可以用-XX: MaxHeapFreeRatio 调整如-X:MaxHeapFreeRatio60时堆内存会开始减少一直减小到-Xms的大小整个堆的大小年轻代大小年老代大小堆的大小不包含持久代大小如果增大了年轻代年老代相应就会减小官方默认的配置为年老代大小/年轻代大小2/1左右使用-XX:NewRatio可以设置-XX:NewRatio5表示年老代/年轻代5/1建议在开发测试环境可以用Xms和Xmx分别设置最小值最大值但是在线上生产环境Xms和Xmx设置的值必须一样原因与年轻代一样——防止抖动 -Xss这个参数用于设置每个线程的栈内存默认1M一般来说是不需要改的。除非代码不多可以设置的小点另外一个相似的参数是-XX:ThreadStackSize这两个参数在1.6以前都是谁设置在后面谁就生效1.6版本以后-Xss设置在后面则以-Xss为准-XXThreadStackSize设置在后面则主线程以-Xss为准其它线程以-XX:ThreadStackSize为准。 -Xrs减少JVM对操作系统信号OS Signals的使用JDK1.3.1之后才有效当此参数被设置之后jvm将不接收控制台的控制handler以防止与在后台以服务形式运行的JVM冲突这个用的比较少参考http://www.blogjava.net/midstr/archive/2008/09/21/230265.html。-Xprof 跟踪正运行的程序并将跟踪数据在标准输出输出适合于开发环境调试。-Xnoclassgc 关闭针对class的gc功能因为其阻止内存回收所以可能会导致OutOfMemoryError错误慎用-Xincgc 开启增量gc默认为关闭这有助于减少长时间GC时应用程序出现的停顿但由于可能和应用程序并发执行所以会降低CPU对应用的处理能力。-Xloggc:file 与-verbose:gc功能类似只是将每次GC事件的相关情况记录到一个文件中文件的位置最好在本地以避免网络的潜在问题。 若与verbose命令同时出现在命令行中则以-Xloggc为准。非Stable参数非静态参数以-XX表示的非Stable参数虽然在官方文档中是不确定的不健壮的各个公司的实现也各有不同但往往非常实用所以这部分参数对于GC非常重要。JVMHotspot中主要的参数可以大致分为3类参考http://blog.csdn.net/sfdev/article/details/2063928 性能参数 Performance Options用于JVM的性能调优和内存分配控制如初始化内存大小的设置行为参数Behavioral Options用于改变JVM的基础行为如GC的方式和算法的选择调试参数Debugging Options用于监控、打印、输出等jvm参数用于显示jvm更加详细的信息比较详细的非Stable参数总结请参考Java 6 JVM参数选项大全中文版对于非Stable参数使用方法有4种 -XX:option 启用选项-XX:-option 不启用选项-XX:optionnumber 给选项设置一个数字类型值可跟单位例如 32k, 1024m, 2g-XX:optionstring 给选项设置一个字符串值例如-XX:HeapDumpPath./dump.core首先介绍性能参数性能参数往往用来定义内存分配的大小和比例相比于行为参数和调试参数一个比较明显的区别是性能参数后面往往跟的有数值常用如下 参数及其默认值描述 -XX:NewSize2.125m 新生代对象生成时占用内存的默认值 -XX:MaxNewSizesize新生成对象能占用内存的最大值-XX:MaxPermSize64m方法区所能占用的最大内存非堆内存-XX:PermSize64m方法区分配的初始内存 -XX:MaxTenuringThreshold15 对象在新生代存活区切换的次数坚持过MinorGC的次数每坚持过一次该值就增加1大于该值会进入老年代 -XX:MaxHeapFreeRatio70 GC后java堆中空闲量占的最大比例大于该值则堆内存会减少 -XX:MinHeapFreeRatio40GC后java堆中空闲量占的最小比例小于该值则堆内存会增加-XX:NewRatio2新生代内存容量与老生代内存容量的比例-XX:ReservedCodeCacheSize 32m保留代码占用的内存容量-XX:ThreadStackSize512设置线程栈大小若为0则使用系统默认值-XX:LargePageSizeInBytes4m 设置用于Java堆的大页面尺寸 -XX:PretenureSizeThreshold size 大于该值的对象直接晋升入老年代这种对象少用为好-XX:SurvivorRatio8Eden区域Survivor区的容量比值如默认值为8代表EdenSurvivor1Survivor28:1:1常用的行为参数主要用来选择使用什么样的垃圾收集器组合以及控制运行过程中的GC策略等 参数及其默认值描述 -XX:-UseSerialGC 启用串行GC即采用SerialSerial Old模式 -XX:-UseParallelGC 启用并行GC即采用Parallel ScavengeSerial Old收集器组合-Server模式下的默认组合 -XX:GCTimeRatio99设置用户执行时间占总时间的比例默认值99即1%的时间用于GC-XX:MaxGCPauseMillistime设置GC的最大停顿时间这个参数只对Parallel Scavenge有效-XX:UseParNewGC使用ParNewSerial Old收集器组合-XX:ParallelGCThreads设置执行内存回收的线程数在UseParNewGC的情况下使用 -XX:UseParallelOldGC 使用Parallel Scavenge Parallel Old组合收集器-XX:UseConcMarkSweepGC使用ParNewCMSSerial Old组合并发收集优先使用ParNewCMS当用户线程内存不足时采用备用方案Serial Old收集。-XX:-DisableExplicitGC禁止调用System.gc()但jvm的gc仍然有效-XX:ScavengeBeforeFullGC新生代GC优先于Full GC执行 常用的调试参数主要用于监控和打印GC的信息 参数及其默认值描述-XX:-CITime打印消耗在JIT编译的时间-XX:ErrorFile./hs_err_pidpid.log保存错误日志或者数据到文件中-XX:-ExtendedDTraceProbes开启solaris特有的dtrace探针-XX:HeapDumpPath./java_pidpid.hprof指定导出堆信息时的路径或文件名-XX:-HeapDumpOnOutOfMemoryError当首次遭遇OOM时导出此时堆中相关信息-XX:OnErrorcmd args;cmd args出现致命ERROR之后运行自定义命令-XX:OnOutOfMemoryErrorcmd args;cmd args当首次遭遇OOM时执行自定义命令-XX:-PrintClassHistogram遇到Ctrl-Break后打印类实例的柱状信息与jmap -histo功能相同-XX:-PrintConcurrentLocks遇到Ctrl-Break后打印并发锁的相关信息与jstack -l功能相同-XX:-PrintCommandLineFlags打印在命令行中出现过的标记-XX:-PrintCompilation当一个方法被编译时打印相关信息-XX:-PrintGC每次GC时打印相关信息-XX:-PrintGC Details每次GC时打印详细信息-XX:-PrintGCTimeStamps打印每次GC的时间戳-XX:-TraceClassLoading跟踪类的加载信息-XX:-TraceClassLoadingPreorder跟踪被引用到的所有类的加载信息-XX:-TraceClassResolution跟踪常量池-XX:-TraceClassUnloading跟踪类的卸载信息-XX:-TraceLoaderConstraints跟踪类加载器约束的相关信息 再次声明上面的三种参数主要参考了博客http://blog.csdn.net/sfdev/article/details/2063928和http://kenwublog.com/docs/java6-jvm-options-chinese-edition.htm后一个比较全面有兴趣的可以仔细研读。这些参数将为我们进行GC的监控与调优提供很大助力是我们进行GC相关操作的重要工具。收集器搭配 在介绍了常用的配置参数之后我们将开始真正的JVM实操征程首先我们要为应用程序选择一个合适的垃圾收集器组合本节请参考《Java系列笔记(3) - Java 内存区域和GC机制》一文中的“垃圾收集器”一节及上节中的行为参数。 这里需要再次引用这幅图图来源于《深入理解Java虚拟机JVM高级特效与最佳实现》图中两个收集器之间有连线说明它们可以配合使用 Serial收集器 Serial收集器是在client模式下默认的新生代收集器其收集效率大约是100M左右的内存需要几十到100多毫秒在client模式下收集桌面应用的内存垃圾基本上不影响用户体验。所以一般的Java桌面应用中直接使用Serial收集器不需要配置参数用默认即可。ParNew收集器Serial收集器的多线程版本这种收集器默认开通的线程数与CPU数量相同-XX:ParallelGCThreads可以用来设置开通的线程数。可以与CMS收集器配合使用事实上用-XX:UseConcMarkSweepGC选择使用CMS收集器时默认使用的就是ParNew收集器所以不需要额外设置-XX:UseParNewGC设置了也不会冲突因为会将ParNewSerial Old作为一个备选方案如果单独使用-XX:UseParNewGC参数则选择的是ParNewSerial Old收集器组合收集器。一般情况下在server模式下如果选择CMS收集器则优先选择ParNew收集器。Parallel Scavenge收集器关注的是吞吐量关于吞吐量的含义见上一篇博客可以这么理解关注吞吐量意味着强调任务更快的完成而如CMS等关注停顿时间短的收集器强调的是用户交互体验。在需要关注吞吐量的场合比如数据运算服务器等就可以使用Parallel Scavenge收集器。老年代收集器如下Serial Old收集器在1.5版本及以前可以与 Parallel Scavenge结合使用事实上也是当时Parallel Scavenge唯一能用的版本另外就是在使用CMS收集器时的备用方案发生 Concurrent Mode Failure时使用。如果是单独使用Serial Old一般用在client模式中。Parallel Old收集器在1.6版本之后与 Parallel Scavenge结合使用以更好的贯彻吞吐量优先的思想如果是关注吞吐量的服务器建议使用Parallel Scavenge Parallel Old 收集器。CMS收集器这是当前阶段使用很广的一种收集器国内很多大的互联网公司线上服务器都使用这种垃圾收集器http://blog.csdn.net/wisgood/article/details/17067203笔者公司的收集器也是这种CMS收集器以获取最短回收停顿时间为目标非常适合对用户响应比较高的B/S架构服务器。 CMSIncrementalMode CMS收集器变种属增量式垃圾收集器在并发标记和并发清理时交替运行垃圾收集器和用户线程。 G1 收集器面向服务器端应用的垃圾收集器计划未来替代CMS收集器。 一般来说如果是Java桌面应用建议采用SerialSerial Old收集器组合即-XX:UseSerialGC-client下的默认参数在开发/测试环境可以采用默认参数即采用Parallel ScavengeSerial Old收集器组合即-XX:UseParallelGC-server下的默认参数在线上运算优先的环境建议采用Parallel ScavengeSerial Old收集器组合即-XX:UseParallelGC在线上服务响应优先的环境建议采用ParNewCMSSerial Old收集器组合即-XX:UseConcMarkSweepGC另外在选择了垃圾收集器组合之后还要配置一些辅助参数以保证收集器可以更好的工作。关于这些参数请在http://kenwublog.com/docs/java6-jvm-options-chinese-edition.htm中查询其意义和用法如 选用了ParNew收集器你可能需要配置4个参数 -XX:SurvivorRatio, -XX:PretenureSizeThreshold, -XX:HandlePromotionFailure,-XX:MaxTenuringThreshold选用了 Parallel Scavenge收集器你可能需要配置3个参数 -XX:MaxGCPauseMillis-XX:GCTimeRatio -XX:UseAdaptiveSizePolicy 选用了CMS收集器你可能需要配置3个参数 -XX:CMSInitiatingOccupancyFraction -XX:UseCMSCompactAtFullCollection, -XX:CMSFullGCsBeforeCompaction启动内存分配 关于GC有一个常见的疑问是在启动时我的内存如何分配经过前面的学习已经很容易知道用-Xmn-Xmx-Xms-Xss-XX:NewSize-XX:MaxNewSize-XX:MaxPermSize-XX:PermSize-XX:SurvivorRatio-XX:PretenureSizeThreshold-XX:MaxTenuringThreshold就基本可以配置内存启动时的分配情况。但是具体配置多少设置小了频繁GC甚至内存溢出设置大了内存浪费。结合前面对于内存区域和其作用的学习尽量考虑如下建议 -XX:PermSize尽量比-XX:MaxPermSize小-XX:MaxPermSize 2 * -XX:PermSize, -XX:PermSize 64m一般对于4G内存的机器-XX:MaxPermSize不会超过256m-Xms -Xmx线上Server模式以防止抖动大小受操作系统和内存大小限制如果是32位系统则一般-Xms设置为1g-2g假设有4g内存在64位系统上没有限制不过一般为机器最大内存的一半左右-Xmn在开发环境下可以用-XX:NewSize和-XX:MaxNewSize来设置新生代的大小-XX:NewSize-XX:MaxNewSize在生产环境建议只设置-Xmn一般-Xmn的大小是-Xms的1/2左右不要设置的过大或过小过大导致老年代变小频繁Full GC过小导致minor GC频繁。如果不设置-Xmn可以采用-XX:NewRatio2来设置也是一样的效果-Xss一般是不需要改的默认值即可。-XX:SurvivorRatio一般设置8-10左右推荐设置为10也即Survivor区的大小是Eden区的1/10一般来说普通的Java程序应用一次minorGC后至少98%-99%的对象都会消亡所以survivor区设置为Eden区的1/10左右能使Survivor区容纳下10-20次的minor GC才满然后再进入老年代这个与 -XX:MaxTenuringThreshold的默认值15次也相匹配的。如果XX:SurvivorRatio设置的太小会导致本来能通过minor回收掉的对象提前进入老年代产生不必要的full gc如果XX:SurvivorRatio设置的太大会导致Eden区相应的被压缩。-XX:MaxTenuringThreshold默认为15也就是说经过15次Survivor轮换即15次minor GC就进入老年代 如果设置的小的话则年轻代对象在survivor中存活的时间减小提前进入年老代对于年老代比较多的应用可以提高效率。如果将此值设置为一个较大值则年轻代对象会在Survivor区进行多次复制这样可以增加对象在年轻代的存活时间增加在年轻代即被回收的概率。需要注意的是设置了 -XX:MaxTenuringThreshold并不代表着对象一定在年轻代存活15次才被晋升进入老年代它只是一个最大值事实上存在一个动态计算机制计算每次晋入老年代的阈值取阈值和MaxTenuringThreshold中较小的一个为准。-XX:PretenureSizeThreshold一般采用默认值即可。监控工具和方法 在JVM运行的过程中为保证其稳定、高效或在出现GC问题时分析问题原因我们需要对GC进行监控。所谓监控其实就是分析清楚当前GC的情况。其目的是鉴别JVM是否在高效的进行垃圾回收以及有没有必要进行调优。通过监控GC我们可以搞清楚很多问题如1minor GC和full GC的频率2执行一次GC所消耗的时间3新生代的对象何时被移到老生代以及花费了多少时间4每次GC中其它线程暂停Stop the world的时间5每次GC的效果如何是否不理想………………监控GC的工具分为2种命令行工具和图形工具常用的命令行工具有注下面的命令都在JAVA_HOME/bin中是java自带的命令。如果您发现无法使用请直接进入Java安装目录调用或者先设置Java的环境变量一个简单的办法为直接运行命令 export PATH$JAVA_HOME/bin:$PATH另外一般的在Linux下下面的命令需要sudo权限在windows下部分命令的部分选项不能使用。1jpsjps命令用于查询正在运行的JVM进程常用的参数为 -q:只输出LVMID省略主类的名称 -m:输出虚拟机进程启动时传给主类main()函数的参数 -l:输出主类的全类名如果进程执行的是Jar包输出Jar路径 -v:输出虚拟机进程启动时JVM参数命令格式:jps [option] [hostid] 一个简单的例子 在上图中有一个vid为309的apache进程在提供web服务。2jstatjstat可以实时显示本地或远程JVM进程中类装载、内存、垃圾收集、JIT编译等数据如果要显示远程JVM信息需要远程主机开启RMI支持。如果在服务启动时没有指定启动参数-verbose:gc则可以用jstat实时查看gc情况。jstat有如下选项 -class:监视类装载、卸载数量、总空间及类装载所耗费的时间 -gc:监听Java堆状况包括Eden区、两个Survivor区、老年代、永久代等的容量以用空间、GC时间合计等信息 -gccapacity:监视内容与-gc基本相同但输出主要关注java堆各个区域使用到的最大和最小空间 -gcutil:监视内容与-gc基本相同但输出主要关注已使用空间占总空间的百分比 -gccause:与-gcutil功能一样但是会额外输出导致上一次GC产生的原因 -gcnew:监视新生代GC状况 -gcnewcapacity:监视内同与-gcnew基本相同输出主要关注使用到的最大和最小空间 -gcold:监视老年代GC情况 -gcoldcapacity:监视内同与-gcold基本相同输出主要关注使用到的最大和最小空间 -gcpermcapacity:输出永久代使用到最大和最小空间 -compiler:输出JIT编译器编译过的方法、耗时等信息 -printcompilation:输出已经被JIT编译的方法命令格式:jstat [option vmid [interval[s|ms] [count]]]jstat可以监控远程机器命令格式中VMID和LVMID特别说明如果是本地虚拟机进程VMID和LVMID是一致的如果是远程虚拟机进程那么VMID格式是: [protocol:][//]lvmid[hostname[:port]/servername]如果省略interval和count则只查询一次查看gc情况的例子 在图中命令sudo jstat -gc 309 1000 5代表着搜集vid为309的java进程的整体gc状态 每1000ms收集一次共收集5次XXXC表示该区容量XXXU表示该区使用量各列解释如下S0CS0区容量S1区相同略S0US0区已使用ECE区容量EUE区已使用OC老年代容量OU老年代已使用PCPerm容量PUPerm区已使用YGCYoung GCMinor GC次数YGCTYoung GC总耗时FGCFull GC次数FGCTFull GC总耗时GCTGC总耗时用gcutil查看内存的例子 图中的各列与用gc参数时基本一致不同的是这里显示的是已占用的百分比如S0为86.53代表着S0区已使用了86.53%3jinfo用于查询当前运行这的JVM属性和参数的值。jinfo可以使用如下选项 -flag:显示未被显示指定的参数的系统默认值 -flag [|-]name或-flag namevalue: 修改部分参数 -sysprops:打印虚拟机进程的System.getProperties() 命令格式:jinfo [option] pid 4jmap用于显示当前Java堆和永久代的详细信息如当前使用的收集器当前的空间使用率等 -dump:生成java堆转储快照 -heap:显示java堆详细信息(只在Linux/Solaris下有效) -F:当虚拟机进程对-dump选项没有响应时可使用这个选项强制生成dump快照(只在Linux/Solaris下有效) -finalizerinfo:显示在F-Queue中等待Finalizer线程执行finalize方法的对象(只在Linux/Solaris下有效) -histo:显示堆中对象统计信息 -permstat:以ClassLoader为统计口径显示永久代内存状态(只在Linux/Solaris下有效) 命令格式:jmap [option] vmid其中前面3个参数最重要如查看对详细信息sudo jmap -heap 309生成dump文件 sudo jmap -dump:file./test.prof 309部分用户没有权限时采用admin用户sudo -u admin -H jmap -dump:formatb,file文件名.hprof pid查看当前堆中对象统计信息sudo jmap -histo 309该命令显示3列分别为对象数量对象大小对象名称通过该命令可以查看是否内存中有大对象有的用户可能没有jmap权限sudo -u admin -H jmap -histo 309 | less5jhat用于分析使用jmap生成的dump文件是JDK自带的工具使用方法为 jhat -J -Xmx512m [file]不过jhat没有mat好用推荐使用matEclipse插件 http://www.eclipse.org/mat mat速度更快而且是图形界面。6jstack用于生成当前JVM的所有线程快照线程快照是虚拟机每一条线程正在执行的方法,目的是定位线程出现长时间停顿的原因。 -F:当正常输出的请求不被响应时强制输出线程堆栈 -l:除堆栈外显示关于锁的附加信息 -m:如果调用到本地方法的话可以显示C/C的堆栈命令格式:jstack [option] vmid 7-verbosegc-verbosegc是一个比较重要的启动参数记录每次gc的日志下面的表格对比了jstat和-verbosegc jstat -verbosegc 监控对象 运行在本机的Java应用可以把日志输出到终端上或者借助jstatd命令通过网络连接远程的Java应用。 只有那些把-verbogc作为启动参数的JVM。 输出信息 堆状态已用空间最大限制GC执行次数/时间等等 执行GC前后新生代和老年代空间大小GC执行时间。 输出时间 Every designated time每次设定好的时间。 每次GC发生的时候。 用途 观察堆空间变化情况 了解单次GC产生的效果。 与-verbosegc配合使用的一些常用参数为 -XX:PrintGCDetails打印GC信息这是-verbosegc默认开启的选项 -XX:PrintGCTimeStamps打印每次GC的时间戳 -XX:PrintHeapAtGC每次GC时打印堆信息 -XX:PrintGCDateStamps (from JDK 6 update 4) 打印GC日期适合于长期运行的服务器 -Xloggc:/home/admin/logs/gc.log制定打印信息的记录的日志位置每条verbosegc打印出的gc日志都类似于下面的格式time [GC [collector: starting occupancy1 - ending occupancy1(total occupancy1), pause time1 secs] starting occupancy3 - ending occupancy3(total occupancy3), pause time3 secs] 如 这些选项的意义是time执行GC的时间需要添加-XX:PrintGCDateStamps参数才有collectorminor gc使用的收集器的名字。starting occupancy1GC执行前新生代空间大小。ending occupancy1GC执行后新生代空间大小。total occupancy1新生代总大小pause time1因为执行minor GCJava应用暂停的时间。starting occupancy3GC执行前堆区域总大小ending occupancy3GC执行后堆区域总大小total occupancy3堆区总大小pause time3Java应用由于执行堆空间GC包括full GC而停止的时间。8可视化工具监控和分析GC也有一些可视化工具比较常见的有JConsole和VisualVM有兴趣的可以看看下面的文章在此不再赘述http://blog.csdn.net/java2000_wl/article/details/8049707调优方法 一切都是为了这一步调优在调优之前我们需要记住下面的原则 多数的Java应用不需要在服务器上进行GC优化多数导致GC问题的Java应用都不是因为我们参数设置错误而是代码问题在应用上线之前先考虑将机器的JVM参数设置到最优最适合减少创建对象的数量减少使用全局变量和大对象GC优化是到最后不得已才采用的手段在实际使用中分析GC情况优化代码比优化GC参数要多得多GC优化的目的有两个http://www.360doc.com/content/13/0305/10/15643_269388816.shtml 将转移到老年代的对象数量降低到最小减少full GC的执行时间为了达到上面的目的一般地你需要做的事情有 减少使用全局变量和大对象调整新生代的大小到最合适设置老年代的大小为最合适选择合适的GC收集器在上面的4条方法中用了几个“合适”那究竟什么才算合适一般的请参考上面“收集器搭配”和“启动内存分配”两节中的建议。但这些建议不是万能的需要根据您的机器和应用情况进行发展和变化实际操作中可以将两台机器分别设置成不同的GC参数并且进行对比选用那些确实提高了性能或减少了GC时间的参数。真正熟练的使用GC调优是建立在多次进行GC监控和调优的实战经验上的进行监控和调优的一般步骤为1监控GC的状态使用各种JVM工具查看当前日志分析当前JVM参数设置并且分析当前堆内存快照和gc日志根据实际的各区域内存划分和GC执行时间觉得是否进行优化2分析结果判断是否需要优化如果各项参数设置合理系统没有超时日志出现GC频率不高GC耗时不高那么没有必要进行GC优化如果GC时间超过1-3秒或者频繁GC则必须优化注如果满足下面的指标则一般不需要进行GC Minor GC执行时间不到50msMinor GC执行不频繁约10秒一次Full GC执行时间不到1sFull GC执行频率不算频繁不低于10分钟1次3调整GC类型和内存分配如果内存分配过大或过小或者采用的GC收集器比较慢则应该优先调整这些参数并且先找1台或几台机器进行beta然后比较优化过的机器和没有优化的机器的性能对比并有针对性的做出最后选择4不断的分析和调整通过不断的试验和试错分析并找到最合适的参数5全面应用参数如果找到了最合适的参数则将这些参数应用到所有服务器并进行后续跟踪。调优实例 上面的内容都是纸上谈兵下面我们以一些真实例子来进行说明实例1笔者昨日发现部分开发测试机器出现异常java.lang.OutOfMemoryError: GC overhead limit exceeded这个异常代表GC为了释放很小的空间却耗费了太多的时间其原因一般有两个1堆太小2有死循环或大对象笔者首先排除了第2个原因因为这个应用同时是在线上运行的如果有问题早就挂了。所以怀疑是这台机器中堆设置太小使用ps -ef |grep java查看发现 该应用的堆区设置只有768m而机器内存有2g机器上只跑这一个java应用没有其他需要占用内存的地方。另外这个应用比较大需要占用的内存也比较多笔者通过上面的情况判断只需要改变堆中各区域的大小设置即可于是改成下面的情况 跟踪运行情况发现相关异常没有再出现实例2http://www.360doc.com/content/13/0305/10/15643_269388816.shtml一个服务系统经常出现卡顿分析原因发现Full GC时间太长jstat -gcutil:S0 S1 E O P YGC YGCT FGC FGCT GCT12.16 0.00 5.18 63.78 20.32 54 2.047 5 6.946 8.993 分析上面的数据发现Young GC执行了54次耗时2.047秒每次Young GC耗时37ms在正常范围而Full GC执行了5次耗时6.946秒每次平均1.389s数据显示出来的问题是Full GC耗时较长分析该系统的是指发现NewRatio9也就是说新生代和老生代大小之比为1:9这就是问题的原因1新生代太小导致对象提前进入老年代触发老年代发生Full GC2老年代较大进行Full GC时耗时较大优化的方法是调整NewRatio的值调整到4发现Full GC没有再发生只有Young GC在执行。这就是把对象控制在新生代就清理掉没有进入老年代这种做法对一些应用是很有用的但并不是对所有应用都要这么做实例3一应用在性能测试过程中发现内存占用率很高Full GC频繁使用sudo -u admin -H jmap -dump:formatb,file文件名.hprof pid 来dump内存生成dump文件并使用Eclipse下的mat差距进行分析发现 从图中可以看出这个线程存在问题队列LinkedBlockingQueue所引用的大量对象并未释放导致整个线程占用内存高达378m此时通知开发人员进行代码优化将相关对象释放掉即可。说明 本文是Java系列笔记的第4篇这篇文章写了近3个月一方面是这部分对我来说也是学习阶段另一方面是这段时间一直在做项目直到最近才比较有时间。 本人能力有限如果有错漏请留言指正。参考资料 《深入理解Java虚拟机JVM高级特效与最佳实现》JVM启动参数大全, http://www.blogjava.net/midstr/archive/2008/09/21/230265.htmlJVM系列三:JVM参数设置、分析, http://www.cnblogs.com/redcreen/archive/2011/05/04/2037057.htmlJava 6 JVM参数选项大全中文版, http://kenwublog.com/docs/java6-jvm-options-chinese-edition.htm成为JavaGC专家Part II — 如何监控Java垃圾回收机制, http://www.importnew.com/2057.html成为Java GC专家系列(3) — 如何优化Java垃圾回收机制, http://www.importnew.com/3146.htmlJDK5.0垃圾收集优化之--Dont Pause, http://calvin.iteye.com/blog/91905Java HOTSPOT VM参数大全, http://tech.sina.com.cn/s/2009-09-23/09561077572.shtml【原】GC的默认方式, http://iamzhongyong.iteye.com/blog/1447314JAVA启动参数大全之三非Stable参数, http://blog.csdn.net/sfdev/article/details/2063928Java虚拟机学习 - 内存调优, http://blog.csdn.net/java2000_wl/article/details/8090940内存溢出, http://www.open-open.com/home/space.php?uid71669doblogid8891如何查看JVM的扩展参数-X, http://www.blogjava.net/beansoft/archive/2012/03/01/371088.htmlJVM内存状况查看方法和分析工具, http://hi.baidu.com/kingfly666666/item/e710a4371c60b0f1e7bb7a32虚拟机学习系列 - 附 - 虚拟机参数, http://blog.csdn.net/su1216/article/details/7780924 JVM系列四:生产环境参数实例及分析【生产环境实例增加中】, http://www.cnblogs.com/redcreen/archive/2011/05/05/2038331.html垃圾收集器与内存分配策略, http://raging-sweet.iteye.com/blog/1170198JVM垃圾收集器使用调查CMS最受欢迎 , http://blog.csdn.net/wisgood/article/details/17067203Xms Xmx PermSize MaxPermSize 区别, http://www.cnblogs.com/mingforyou/archive/2012/03/03/2378143.htmlJava虚拟机学习 - JDK可视化监控工具, http://blog.csdn.net/java2000_wl/article/details/8049707虚拟机学习系列 - 6 - JDK工具, http://blog.csdn.net/su1216/article/details/7780857JVM监控工具介绍jstack, jconsole, jinfo, jmap, jdb, jstat, http://hi.baidu.com/lotusxyhf/item/9cd8fcb8d6f8c1a5ebba935bJVM 与 jstat, http://blog.sina.com.cn/s/blog_56fcfd620100hdcp.html 转载于:https://www.cnblogs.com/abcd19880817/p/7193876.html