`
chinese.darren
  • 浏览: 101126 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

性能监控/优化系列——JVM监控/调优

阅读更多

 JVM监控

1. ParNew表示CMS收集器在新生代采用多线程进行垃圾回收。DefNew表示顺序垃圾收集器在新生代采用单线程进行垃圾回收。
2.系统做完CMS cycle后,观察minorGC的日志,如果日志中发现CMS收集前后的heap占用下降不明显,那要么是已有的对象太少,以至于找到的unreachable对象很少,这样浪费费CPU;要么是对象从新生代提拔到老生代的速率超过了CMS所能承受的范围。总之,出现以上情况表示需要进行性能调优。
3. -XX:+CMSClassUnloadingEnabled -XX:+CMSPermGenSweepingEnabledPermGen一般存放一些JVM的元数据(Class/反射代理等),比如Spring/Hibernate大量采用cglib,导致生成的Proxy会比较多,而这些都是存放在PermGen区域,默认情况下CMS不会去做回收,因此,为了保证PermGen空间正常可以设置以上两个参数实现垃圾的回收。另外,-XX:CMSInitiatingPermOccupancyFraction=<percent>可以知道持久代的占用百分比。
4. -XX:MaxTenuringThreshold=10,意思是说对象在survivor区域中经过10minorGC还存活的话就提拔到老生代。再比如 -XX:SurvivorRatio=65536 -XX:MaxTenuringThreshold=0这样的配置实际上就是去掉了survivor区域,直接将对象从eden区域提拔到老生代。
5. 在CMS中如果监控到它的两个暂停阶段initial mark or remark的暂停时间比一次minorGC的暂停时间还长,那么需要进行性能优化。
6. 当fullGC发生时伴随着持久代class的unload,那么需要考虑调大持久代空间的大小。
 
[Full GC[Unloading class sun.reflect.GeneratedConstructorAccessor3]
[Unloading class sun.reflect.GeneratedConstructorAccessor8]
[Unloading class sun.reflect.GeneratedConstructorAccessor11]
[Unloading class sun.reflect.GeneratedConstructorAccessor6]
8566K->5871K(193856K), 0.0989123 secs]
7. 使用jstack去挖掘锁竞争的方法:Observing multiple thread stack traces trying to lock the same lock address is an indication the application is experiencing lock contention,查看那些处在同一lock地址上的线程栈。     
8. JVM监控常用到的命令:-XX:+PrintGCDetails、-XX:+PrintGCTimeStamps、-XX:+PrintGCDateStamps、-Xloggc:<filename>、-XX:+PrintGCApplicationConcurrentTime and -XX:+PrintGCApplicationStoppedTime。
9.JVM监控常用的可视化工具:GCHisto、JConsolejvisualvm
JVM调优
方法论
1.The client runtime is specialized for rapid startup, small memory footprint, and a JIT compiler with rapid code generation。The server runtime offers
more sophisticated code generation optimizations, which are more desirable in server applications。现在还出来一个新的runtime—tiered,但是还不成熟,tiered combines the best of the client and server runtimes, that is, rapid startup time and high performing generated code。
2. 选择JVM为32bit还是64bit取决于内存和第三方本地库的使用,All native components using the Java Native Interface (JNI) in a 64-bit JVM must be compiled in 64-bit mode。
3. -XX:+UseParallelOldGC 和 -XX:+UseParallelGC的区别:前者会启动新生代和老生代的多线程收集;而后者只启动新生代的多线程收集,老生代是单线程的。
4. 决定JVM性能的属性:1. 吞吐量;2. 延时(latency);3.内存占用量
5. JVM调优的三原则:1. Minor GC Reclamation Principle—在minorGC时要最大化回收对象数;2. GC Maximize Memory Principle;3. 2 of 3 GC Tuning
Principle—调优点放在占总性能2/3的几个属性上:吞吐量/延时(latency)/内存占用量。
6. 推荐的GC日志配置:-XX:+PrintGCTimeStamps -XX:+PrintGCDetails -Xloggc:<filename> 如果要调优为低延时, -XX:+PrintGCApplicationStoppedTime(GC时应用暂停的时间)、-XX:+PrintGCApplicationConcurrentTime(GC时应用并发执行的时间)很有用。、
推荐的log配置:
7.  当-Xmx 和-Xms不相同时,堆size可能会发生作自动调整,但是调整时,并不会调整新生代的大小。因此-Xmn只能用于-Xmx 和-Xms拥有相同值。事实上,把-Xmx 和-Xms设置为相同的值是一个好的习惯。
8. -XX:-ScavengeBeforeFullGC可以避免fullGC时收集新生代。
9. jmap -histo:live pid命令可以强制执行一次fullGC。
10. GC时,以下因素影响到延时:1. 一次minorGC的持续时间;2. minorGC的频率;3. 一次fullGC的持续时间;4. fullGC的频率;1和2决定了是否需要重新定义young generation size。3和4决定了是否需要重新定义old generation size,及是否要启用并发GC(-XX:+UseConcMarkSweepGC)。
11. 可以通过像下面这样的gclog来计算平均minorGC发生频率和平均持续时间,如果发现平均平均持续时间〉期望的应用延时时间,那么就需要进一步调优:
12. 当需要调优某一个代的size时,一般不要改变其他代的大小,而是通过调整堆堆和要调优的代的大小来实现。
13. 关于各代size的大小,请关注以下guidelines:
     1)The old generation space size should be not be much smaller than 1.5x the live data size。
     2) Young generation space size should be at least 10% of the Java heap size, the value specified as -Xmx and -Xms。
     3)When increasing the Java heap size, be careful not to exceed the amount of physical memory available to the JVM。
14. 提拔率的计算: rate=每秒提拔到老生代的数据量=每次minorGC提拔的数据量/收集频率(s)=minorGC前后老生代空间占用量之差/收集频率(s)。如果知道现在老生代剩余的空间(用y代表),那么就可以计算出可以算出多久后,这些剩余的空间会被提拔的对象占满,公式为:m(s)=y/rate,这个m值就应该是fullGC的理想频率。
15. 对CMS的调优重点是:avoid a stop-the-world compacting garbage collection。
16. 从其它垃圾收集器转到CMS时,一个常见的原则是扩大原有老生代20%-30%。
17. 调优CMS要注意三个元素:提拔率、fragmentation(live对象之间的hole)、并发线程回收率。解决fragmentation的一种方法就是compacting 内存,但是会造成很大的延时(这个就是叫stop-the-world ),另一个解决方法是增大内存空间(使用Maximize Memory Principle),这不能完全解决fragmentation问题,但是能够减少发生的频率,最后一个方法是减低提拔率(这个可以使用Minor GC Reclamation Principle)。
Survivor的调优:
18. survivor space计算公式:survivor space size = -Xmn<value>/(-XX:SurvivorRatio=<ratio> + 2)。
19. Tenuring Threshold的概念:每次minorGC时都会计算该值,看啥时能够将一个对象提拔到老生代,它的值其实就是对象age(经历的minorGC数),对象被分配时的age=0。如果某个时刻对象的age大于Tenuring Threshold就会被提拔到老生代。事实上,-XX:MaxTenuringThreshold=<n>命令可以指定这个值(该值的范围:ranging from 0–15 for Java 5 Update 6 and later, 0–31 for Java 5 Update 5 and earlier),default maximum value=15
20. 如果需要Tenuring Threshold监控的值,可以通过下面命令启动-XX:+PrintTenuringDistribution。下面是日志格式,其中,Desired survivor size 8388608 bytes的值=一个survivor大小*target survivor ratio(target survivor space occupancy,默认值为50%)。要保证survivor能够容纳16690480 total的live对象需要survivor拥有16690480 /50% = 33,380,960的空间也就是32M。假设原来的配置为:-Xmx1536m -Xms1536m -Xmn512m -XX:SurvivorRatio=30,现在我们采用增加新生代空间不动eden空间的调优方式,那么配置应该变成-Xmx1568m -Xms1568m -Xmn544m -XX:SurvivorRatio=15。注意Xmn变为了544(512+32),SurvivorRatio=15=544/32-2。当然也可以通过不动新生代空间减小eden空间的办法,但还是尽量使用第一种方法。
-XX:TargetSurvivorRatio=<percent>能够指定target survivor space occupancy,默认值为50%。
Desired survivor size 8388608 bytes, new threshold 1 (max 15)
- age 1: 16690480 bytes, 16690480 total
21. 以下现象暗示survivor的空间太小:1. new tenuring threshold<max tenuring threshold;2.  desired survivor size(见上图)< total surviving bytes数。
从上图来看,1〈15;8388608<16690480所以需要调优survivor大小。再看下图,15==15;16777216>7320248所以是一个比较合理的survivor配置。
Desired survivor size 16777216 bytes, new threshold 15 (max 15)
- age 1: 6115072 bytes, 6115072 total
- age 2: 286672 bytes, 6401744 total
- age 3: 115704 bytes, 6517448 total
- age 4: 95932 bytes, 6613380 total
- age 5: 89465 bytes, 6702845 total
- age 6: 88322 bytes, 6791167 total
- age 7: 88201 bytes, 6879368 total
- age 8: 88176 bytes, 6967544 total
- age 9: 88176 bytes, 7055720 total
- age 10: 88176 bytes, 7143896 total
- age 11: 88176 bytes, 7232072 total
- age 12: 88176 bytes, 7320248 total
CMS的调优:
22. CMS garbage collector的调优主要目标是保持老生代有足够可获得的空间和后续避免stop-the-world compacting garbage collections。
23. concurrent mode failure暗示了Stop-the-world compacting garbage collections in CMS,如下图,如果发生了这种情况需要通过命令-XX:CMSInitiatingOccupancyFraction=65(这里表示老生代空间占用65%修改CMS garbage collection cycle启动时间。另外还有一个相关的命令-XX:+UseCMSInitiatingOccupancyOnly,它保证所有的CMS garbage collection cycle都按照设定的比例来启动,如果没有设置后者,那么仅有第一个CMS garbage collection cycle是按照设定的比例启动,之后会根据JVM自适应的方式调整启动时间。建议一起使用这两个命令。
CMSInitiatingOccupancyFraction值应该大于live data size(一个fullGC后heap的占用量),如果小于这个值,那么CMS collector会运行得过于频繁。一个经验值是至少1.5倍live data size。
174.445: [GC 174.446: [ParNew: 66408K->66408K(66416K), 0.0000618
secs]174.446: [CMS (concurrent mode failure): 161928K->162118K(175104K),
4.0975124 secs] 228336K->162118K(241520K)
24. 如果观察到CMS-initial-mark——〉CMS-concurrent-reset过程中heap的占用变化不大(比如说就几M或几十M),说明CMS cycle工作的太早,表示需要通过-XX:CMSInitiatingOccupancyFraction and -XX:+UseCMSInitiatingOccupancyOnly来增大老生代空间占用率。296358K-〉292925K变化不大。
[ParNew 390868K->296358K(773376K), 0.1882258 secs]
[CMS-initial-mark 298458K(773376K), 0.0847541 secs]
[ParNew 401318K->306863K(773376K), 0.1933159 secs]
[CMS-concurrent-mark: 0.787/0.981 secs]
[CMS-concurrent-preclean: 0.149/0.152 secs]
[CMS-concurrent-abortable-preclean: 0.105/0.183 secs]
[CMS-remark 374049K(773376K), 0.0353394 secs]
[ParNew 407285K->312829K(773376K), 0.1969370 secs]
[ParNew 405554K->311100K(773376K), 0.1922082 secs]
[ParNew 404913K->310361K(773376K), 0.1909849 secs]
[ParNew 406005K->311878K(773376K), 0.2012884 secs]
[CMS-concurrent-sweep: 2.179/2.963 secs]
[CMS-concurrent-reset: 0.010/0.010 secs]
[ParNew 387767K->292925K(773376K), 0.1843175 secs]
下面这个就比较正常了,546360K-〉350518K变化比较大。
[ParNew 640710K->546360K(773376K), 0.1839508 secs]
[CMS-initial-mark 548460K(773376K), 0.0883685 secs]
[ParNew 651320K->556690K(773376K), 0.2052309 secs]
[CMS-concurrent-mark: 0.832/1.038 secs]
[CMS-concurrent-preclean: 0.146/0.151 secs]
[CMS-concurrent-abortable-preclean: 0.181/0.181 secs]
[CMS-remark 623877K(773376K), 0.0328863 secs]
[ParNew 655656K->561336K(773376K), 0.2088224 secs]
[ParNew 648882K->554390K(773376K), 0.2053158 secs]
[ParNew 489586K->395012K(773376K), 0.2050494 secs]
[ParNew 463096K->368901K(773376K), 0.2137257 secs]
[CMS-concurrent-sweep: 4.873/6.745 secs]
[CMS-concurrent-reset: 0.010/0.010 secs]
[ParNew 445124K->350518K(773376K), 0.1800791 secs]
[ParNew 455478K->361141K(773376K), 0.1849950 secs]
说明CMS cycle工作的太晚的例子(下图),CMS周期还没有走完就马上执行了fullGC。因此要减小XX:CMSInitiatingOccupancyFraction。
[ParNew 742993K->648506K(773376K), 0.1688876 secs]
[ParNew 753466K->659042K(773376K), 0.1695921 secs]
[CMS-initial-mark 661142K(773376K), 0.0861029 secs]
[Full GC 645986K->234335K(655360K), 8.9112629 secs]
[ParNew 339295K->247490K(773376K), 0.0230993 secs]
[ParNew 352450K->259959K(773376K), 0.1933945 secs]
总之,要得到一个合理的CMSInitiatingOccupancyFraction值需要设置各种尝试值,然后观察日志数据,最终方可作出选择。
25. 以下日志内容表明系统进行了显示的fullGC(System.gc()),RMI应用会在某些时刻执行显示GC。
[Full GC (System)
[CMS: 418061K->428608K(16384K), 0.2539726 secs]
418749K->4288608K(31168K),
[CMS Perm : 32428K->32428K(65536K)],
0.2540393 secs]
[Times: user=0.12 sys=0.01, real=0.25 secs]
26. -XX:ParallelGCThreads=<n>也能决定CMS中并发rermark线程数。在Java 6 Update 23中,ParallelGCThreads的默认值为:如果Runtime.availableProcessors()地值小于等于8,其值就是处理器的数目,否则,其值为处理数目*5/8。当机器上还运行有其他的应用时,需要将该值调整小于默认值。
27. -XX:+CMSScavengeBeforeRemark可以减少remark的duration值,因为老生代的对象有的会依赖于新生代的对象,当增加了这个命令时会在remark之前执行一次minorGC的操作,从而可以减少老生代到新生代的reachable对象数。
28. 如果应用有很多的Reference or finalizable objects,那么可以使用-XX:+ParallelRefProcEnabled来减少duration。
并行GC的调优:
29. 并行GC的调优主要是让其避免fullGC。
30. 并行GC支持(仅它支持)UseAdaptiveSizePolicy,它会自动地去调整新生代的空间,因此在对并行GC进行调优时需要关闭它-XX:-UseAdaptiveSizePolicy。调优前先要监控日志,使用如下配置:-XX:+PrintGCDateStamps, -XX:PrintGCDetails,-XX:+PrintAdaptiveSizePolicy。
31.当发生fullGC,首先确认old generation space是否大于等于1.5倍live data size,如果小就增大。其次查看日志看是否有overflow: true,如果有说明老生代空间不够大,或者说是survivor的空间太小。
 
[GCAdaptiveSizePolicy::compute_survivor_space_size_and_thresh:
survived: 446113911
promoted: 10904856
overflow: true
[PSYoungGen: 6493788K->233888K(9437184K)]
7959281K->2662511K(13631488K), 0.0797732 secs]
[Times: user=0.59 sys=0.00, real=0.08 secs]
32. 调优survivor空间,通过多次观察找到一个最大的sruvivored值(来自于上面的日志)假设这个值为500M,那么需要的survivor空间大小=500M/50%(TargetSurvivorRatio的默认值为50%)=1G。然后根据这个值来调整head的大小(在内存还可分配的情况下,尽量不要动老生代/eden空间的大小)。当没有办法下需要缩小老生代空间时必须保证老生代的空间值为1.5倍于live data size。如果实在内存紧张也可以考虑增大TargetSurvivorRatio值。
33. 一条原则:并行GC的开销不应该大于5%。
其他方面:
1. 如果应用有大的分配率,但是这些对象的存活期却很短,需要考虑更大的新生代空间,甚至超过老生代。
2. 如果应用的提拔率很低,那么可以考虑让old generation space<live data size。
3. 逃逸分析——Escape Analysis。-XX:+DoEscapeAnalysis
4. 偏向锁——Biased Locking。
5. 大内存页——Large Pages。
分享到:
评论
1 楼 blackproof 2015-03-24  
你好,age后边的两个数,是啥意思
Desired survivor size 16777216 bytes, new threshold 15 (max 15) 
- age 1: 6115072 bytes, 6115072 total 
- age 2: 286672 bytes, 6401744 total 
- age 3: 115704 bytes, 6517448 total 

相关推荐

    实战Java虚拟机——JVM故障诊断与性能优化.pdf

    通过阅读《实战Java虚拟机——JVM故障诊断与性能优化》,读者不仅可以学习到JVM的基础知识,还能掌握如何在实际工作中诊断问题和优化性能,从而提升Java应用程序的运行效率和稳定性。这本书是Java开发者深入理解JVM...

    JAVA JVM性能调优监控工具详解

    本文介绍了两种常见的JVM性能调优监控工具——`jps`和`jstack`的基本使用方法及实际应用场景。这些工具可以帮助开发者快速定位问题所在,提高系统的稳定性和响应速度。此外,对于更复杂的性能问题,还可以结合其他...

    学习笔记——JVM性能调优之 jstat(csdn)————程序.pdf

    总之,jstat是JVM性能监控的得力工具,通过熟练运用它可以深入了解JVM的运行状况,从而进行有效的性能优化。在实际工作中,结合JVisualVM、JConsole等可视化工具,可以更全面地分析和调优Java应用的性能。

    实战Java虚拟机——JVM故障诊断与性能优化

    理解这些部分的工作方式有助于定位问题和优化性能。 2. **内存管理**:JVM内存主要分为堆内存和栈内存,其中堆内存用于对象实例的存储,栈内存则处理方法调用。了解内存分配、GC(Garbage Collection)策略以及内存...

    JVM调优实战.doc

    调优过程中会观察JVM监控图,分析性能瓶颈,并根据测试结果进行参数调整。文中还提供了一个性能问题的案例分析,展示了从症状到原因分析,再到JVM配置优化的完整过程。 性能问题的分析通常涉及监控结果的解读,例如...

    JVM性能调优-JVM内存整理及GC回收.pdf_java_jvm_

    《JVM性能调优——JVM内存整理及GC回收》是针对Java开发人员的重要主题,尤其是在大型企业级应用中,确保JVM(Java虚拟机)的高效运行是至关重要的。本资料深入探讨了如何通过调整JVM内存设置和优化垃圾回收机制来...

    实战JAVA虚拟机 JVM故障诊断与性能优化

    《实战JAVA虚拟机 JVM故障诊断与性能优化》这本书主要涵盖了Java开发者在实际工作中可能遇到的JVM相关问题,包括但不限于故障排查、性能调优、内存管理、垃圾收集机制等内容。以下将详细介绍这些知识点: 1. **Java...

    JVM调优工具分享

    总的来说,JConsole和VisualVM都是强大的JVM监控工具,它们提供了丰富的功能来协助开发者进行性能优化。JConsole简洁易用,适合日常的基本监控;而VisualVM则更为全面,尤其在插件的支持下,可以进行深入的性能分析...

    eclipse性能优化 <深度理解jvm>读书笔记

    同样,调整Maven或Gradle构建设置,如分批构建,也可以优化性能。 接下来,我们转向《深度理解JVM》的相关知识点: 1. **JVM内存模型**:JVM内存分为堆(Heap)、栈(Stack)、方法区(Method Area)、程序计数器...

    深入JVM内核—原理、诊断与优化视频教程-3.常用JVM配置参数

    本教程——“深入JVM内核—原理、诊断与优化视频教程”,将重点讲解这些关键点,帮助开发者提升技术水平,更好地解决实际问题。 首先,我们来探讨JVM的内核原理。JVM主要由类加载子系统、运行时数据区、执行引擎、...

    websphere性能调优

    通过对CPU利用率、内存使用情况、线程状态、JVM垃圾回收等关键指标的监控,可以快速定位潜在的性能瓶颈,为后续的调优工作提供数据支持。 ### 性能调优的一般步骤 性能调优是一个迭代的过程,通常遵循以下步骤:...

    Java虚拟机-jvm故障诊断与性能优化-源码

    在《实战Java虚拟机——JVM故障诊断与性能优化》一书中,作者深入探讨了如何对JVM进行故障排查和性能调优,通过源码分析来帮助读者理解其内部工作原理。下面我们将根据书中的主题,详细阐述相关的知识点。 1. **JVM...

    jvm调优

    此外,JConsole和VisualVM也都是常用的JVM监控工具。 在实际调优过程中,我们还需要关注JVM的一些关键参数。例如,-Xms和-Xmx用于设置堆内存的初始和最大值,-XX:NewRatio定义新生代和老年代的比例,-XX:...

    JVM监控,调优,分析工具(低配版arthas)-spectre.zip

    本压缩包"JVM监控,调优,分析工具(低配版arthas)-spectre.zip"提供了一个轻量级的Arthas版本——Spectre,它可以帮助开发者在资源有限的环境中进行JVM的监控、调优和分析。 Spectre,这个名字源于电影《007》系列...

    老调重弹 之 性能调优

    标题中的“老调重弹 之 性能调优”暗示了我们将探讨的是一个永恒的话题——如何优化程序的性能。在软件开发中,性能优化是一个关键环节,它涉及到代码的效率、资源的利用以及用户体验等多个方面。对于Java开发者来说...

    jvm参数调优-jvmSample.zip

    《JVM参数调优——深度解析与实践指南》 在Java开发中,JVM(Java Virtual Machine)扮演着至关重要的角色。它不仅负责执行Java代码,还管理内存、线程等资源,确保程序的高效运行。然而,如果不合理地配置JVM参数...

    jvisualvm来JVM监控

    《使用jvisualvm进行JVM监控与调优详解》 在Java开发中,JVM(Java Virtual Machine)的性能监控和调优是至关重要的环节,它直接影响到应用程序的运行效率和稳定性。jvisualvm,作为Oracle JDK自带的一款强大的性能...

    JAVA性能调优

    在性能调优中,我们需要监控 JVM 运行状况,了解 CPU、内存的占用率以及网络使用情况等,发现系统瓶颈——内存瓶颈、CPU 负载过大、网络阻塞等。这些信息可以通过 JDK 自带的监控工具来获取。 JDK 自带了一些帮助...

    Java程序性能优化 让你的Java程序更快、更稳定

    1. **JVM调优**:Java虚拟机(JVM)是Java程序运行的基础,优化JVM参数可以显著提升性能。例如,调整堆内存大小(-Xms和-Xmx),设置新生代和老年代的比例(-XX:NewRatio),以及开启或关闭垃圾回收器(如G1、Parallel ...

Global site tag (gtag.js) - Google Analytics