Java垃圾收集调优实战

2019-03-17 23:26|来源: -- --

1 资料

2 GC日志打印

GC调优是个很实验很伽利略的活儿,GC日志是先决的数据参考和最终验证:

-XX:+PrintGCDetails -XX:+PrintGCTimeStamps(GC发生的时间) -XX:+PrintGCApplicationStoppedTime(GC消耗了多少时间) -XX:+PrintGCApplicationConcurrentTime(GC之间运行了多少时间)



3 收集器选择

   CMS收集器:暂停时间优先

      配置参数:-XX:+UseConcMarkSweepGC
      已默认无需配置的参数:-XX:+UseParNewGC(Parallel收集新生代) -XX:+CMSPermGenSweepingEnabled(CMS收集持久代) -XX:UseCMSCompactAtFullCollection(full gc时压缩年老代)

  初始效果:1g堆内存的新生代约60m,minor gc约5-20毫秒,full gc约130毫秒。

   Parallel收集器:吞吐量优先

       配置参数: -XX:+UseParallelGC -XX:+UseParallelOldGC(Parallel收集年老代,从JDK6.0开始支持)

       已默认无需配置的参数: -XX:+UseAdaptiveSizePolicy(动态调整新生代大小)

       初始效果:1g堆内存的新生代约90-110m(动态调整),minor gc约5-20毫秒,full gc有无UseParallelOldGC 参数分别为1.3/1.1秒,差别不大。

      另外-XX:MaxGCPauseMillis=100 设置minor gc的期望最大时间,JVM会以此来调整新生代的大小,但在此测试环境中对象死的太快,此参数作用不大。


4 调优实战

Parallel收集高达1秒的暂停时间基本不可忍受,所以选择CMS收集器。

在被压测的Mule 2.0应用里,每秒都有大约400M的海量短命对象产生:

  1. 因为默认60M的新生代太小了,频繁发生minor gc,大约0.2秒就进行一次。

  2. 因为CMS收集器中MaxTenuringThreshold(生代对象撑过过多少次minor gc才进入年老代的设置)默认0,存活的临时对象不经过Survivor区直接进入年老代,不久就占满年老代发生full gc。

对这两个参数的调优,既要改善上面两种情况,又要避免新生代过大,复制次数过多造成minor gc的暂停时间过长。

  1. 使用-Xmn调到1/3 总内存。观察后设置-Xmn500M,新生代实际约460m。(用-XX:NewRatio设置无效,只能用 -Xmn)。

  2. 添加-XX:+PrintTenuringDistribution 参数观察各个Age的对象总大小,观察后设置-XX:MaxTenuringThreshold=5。

     优化后,大约1.1秒才发生一次minor gc,且速度依然保持在15-20ms之间。同时年老代的增长速度大大减缓,很久才发生一次full gc,

     参数定稿:

 -server -Xms1024m -Xmx1024m -Xmn500m -XX:+UseConcMarkSweepGC   -XX:MaxTenuringThreshold=5  -XX:+ExplicitGCInvokesConcurrent


     最后服务处理速度从1180 tps 上升到1380 tps,调整两个参数提升17%的性能还是笔很划算的买卖。


    另外,JDK6 Update 7自带了一个VisualVM工具,内里就是之前也有用过的Netbean Profiler,类似JConsole一样使用,可以看到线程状态,内存中对象以及方法的CPU时间等调优重要参考依据。免费捆绑啊,Sun 这样搞法,其他做Profiler的公司要关门了。


转自:http://calvin.iteye.com/blog/212967


相关问答

更多
  • tomcat调优[2022-12-12]

    我没有 视频,只有资料 java.lang.OutOfMemoryError: PermGen space及其解决方法 1、 PermGen space的全称是Permanent Generation space,是指内存的永久保存区域OutOfMemoryError: PermGen space从表面上看就是内存益出,解决方法也一定是加大内存。说说为什么会内存益出:这一部分用于存放Class和Meta的信息,Class在被 Load的时候被放入PermGen space区域,它和和存放Instance的H ...
  • 这种工具书,建议还是买实体书吧,即翻即用。各大网店也都有卖。 另外这本书,真的很棒。我也是从事Linux运维的。
  • 本书是一线DBA技术专家精心之作。积作者多年的经验结晶和*佳实践。 也是目前市场上为数不多通过存储原理来讲解性能优化,剖析SQL Server架构,从而帮助读者快速高效调优数据库的图书。
  • oracle怎么调优[2023-09-03]

    简单些方法就是用oracle自带的工具 调整sga和pga把命中率提高到90以上就可以 了
  • Java自动调用垃圾收集器,那么为什么我们需要手动调用垃圾收集? 我们不需要它们。 事实上,在大多数情况下调用System.gc() 对应用程序性能有害 。 有关详细解释,请参阅我的回答“为什么调用system gc是一个糟糕的做法” 。 什么时候应该使用System.gc() 如果应用程序知道它正在进入一个没有别的事情要做的阶段,并且用户不太可能注意到垃圾回收,那么也许可以调用System.gc()来阻止用户遇到GC暂停在将来。 缺点包括: 调用System.gc()通常会触发一个完整的GC,它比“新空间 ...
  • 因为下面的行由于b1&b2 refrences指向的对象仍然存在引用。 a1.b1 = b1 ; a1.b2 = b1 ; a2.b2 = b2 ; 像这样假设: b1--->BetaObj1 b2---BetaObj2 a1---> AlphaObj1 a2---> AlphaObj2 a1.b1指向b1,意思是说,有对BetaObj1的引用a1.b2指向b1,这意味着还有另一个对BetaObj1的引用 (此时有3个对BetaObj1的引用) a2.b2指向b2,这意味着, ...
  • 看看http://developers.sun.com/mobility/midp/articles/garbage/ 随着Java技术在电信(电信)行业中越来越普遍,理解垃圾收集器的行为变得更加重要。 通常,电信公司应用程序是近实时应用程序。 以毫秒为单位测量的延迟通常不是问题,但延迟数百毫秒(更不用说秒数)可能会给这类应用带来麻烦。 很简单,次优性能直接转化为收入损失。 基本上,如果垃圾收集器压缩一个小堆,那么延迟很短,但如果你一直在生成大量垃圾,并且有一个大的可达对象图,你可以看到很大的延迟。 新的垃 ...
  • 正确。 事实上,没有垃圾收集器方法( System.gc()是一个提示,现在可能是垃圾收集的好时机,但它只不过了)。 JVM,如果它实现垃圾收集(以及所有Java SE和Java EE那些),它将根据自己的规则进行收集,这些规则通常包括同时清理短期对象,并在内存开始变低时执行主要收集或支离破碎。 Correct. In fact, there is no garbage-collector method (System.gc() is a hint that now might be a good time ...
  • 如果您检查4个引用对象,那么当您的对象变为“符合垃圾回收条件”时,会通知您。 这意味着你不必等待一个“大”GC,即使它在一个老一代领域,它也可以让你在一次小通过期间知道物体是否无法到达。 我相信这应该是你正在尝试的正确方法。 If you examine the 4 reference objects, there is one that will notify you when your object becomes "Eligible for garbage collection". This mean ...
  • 垃圾收集器确定哪些对象可从本地和全局变量和数据结构访问,并且这些对象不是垃圾。 在超时函数的情况下,它们可以从事件队列访问,事件队列是Javascript实现内部的全局数据结构。 The garbage collector determines which objects are reachable from local and global variables and data structures, and those objects are not garbage. In the case of ti ...