java g1 收集调优
JVM背后发生了什么,垃圾回收如何影响Java性能?
性能调优世界是一个危险的地方,一个JVM标志失衡,事情很快就会变得繁琐。 因此 ,我们决定求助于Java性能调优专家, 单调 JVM探查器mjprof的创建者Haim Yadid 。 在这篇文章中,我们将分享他在实践中经受住考验的一些见解,并了解JVM内部在压力下的表现。
新帖:Java性能优化–如何最大程度地利用垃圾收集器http://t.co/NnzQpuWBHz pic.twitter.com/8zqMrUfSHl
— Takipi(@takipid) 2015年4月2日
了解您要面对的问题
JVM受到垃圾回收暂停的影响,该暂停的频率和持续时间各不相同。 在暂停过程中,一切都停止了,各种意外行为开始发挥作用。 当面对一个新的调优项目时,通常会发生以下两种情况之一:公司已经知道它存在垃圾回收问题,或者很快就会发现它有一个问题。 在此阶段,他们很可能会出现暂停,JVM卡住的不稳定行为以及性能普遍下降。 这些症状通常是通过响应时间慢,CPU和内存利用率高或系统在大多数情况下正常运行而具有异常行为(例如,极其缓慢的事务和断开连接)而可见的。
主要陷阱:忽略异常值
可以通过一种常见的错误来忽略这种行为,并且不会向任何人发出警报,这是一个常见的错误:测量平均交易时间,并忽略异常值。 这就是隐藏GC问题的地方:尽管大多数情况下系统可能表现正常,但有时其他系统的响应能力却会下降,并给许多用户带来不好的体验。 例如,一个通常需要100毫秒的事务会受到GC暂停的影响,并突然花费几秒钟甚至一分钟。 在电子商务站点中,如果系统的维护人员仅查看平均交易时间,则除用户以外的任何人都不会注意到这一点。 另一个很容易忽略的问题是,当系统吞吐量受到影响时(例如命中率达到20%),并且它无法发挥其潜力。 您可能永远不会知道出了什么问题,因为您没有查看正确的指标。 很多时候,原因是对GC开销的了解不足,并且只关注平均响应时间的一个指标,而忽略了第99个百分位数。
定义性能要求:频率和持续时间
这里的主要问题是:您认为应用程序中GC暂停频率和持续时间的可接受标准是什么? 例如,每天暂停15秒可能是可以接受的,而30分钟一次的频率对产品来说绝对是灾难。 这些要求来自每个系统的领域,在这些领域中,实时和高频交易系统将具有最严格的要求。
总体而言,看到15到17秒的停顿并不罕见。 某些系统甚至可能达到40-50秒的暂停,Haim也有机会在具有大量批处理工作的大堆的系统中看到5分钟的暂停。 因此,暂停持续时间在这里并不重要。
停止世界收集数据:GC日志的重要性
在基于HotSpot JVM的系统中,垃圾收集状态最丰富的数据源是GC日志。 如果您的JVM没有生成带有时间戳的GC日志,那么您就错过了用于分析和解决暂停问题的重要数据源。 这对于开发环境,登台,负载测试以及最重要的是在生产中都是如此。 您可以获取有关系统中所有GC事件的数据,无论这些事件是同时完成的还是导致世界停顿的:这些事件花费了多长时间,消耗了多少CPU以及释放了多少内存。 从这些数据中,您可以了解这些暂停的频率和持续时间,它们的开销,并继续采取行动来减少它们。
-XX:+PrintGCDetails -XX:+PrintGCDateStamps -Xloggc:mygclogfilename.gc
GC日志数据收集的最低设置
从指标来看,5%通常是可接受的GC开销的上限,而一个应用程序与另一个应用程序之间可接受的暂停时间却大不相同。
这里值得提及的两个用于GC日志分析的工具是Github上可用的开源GC Viewer和jClarity的Censum 。
解决方案策略
获得所需信息后,就可以检查可能的原因和解决方案了。 您进行的每项更改都要求进行一次新测试,并进行一轮日志收集,以评估其有效性并确定它是否有助于我们前进并达到要求。 优选在生产中和在压力下。 我们可以通过4种主要方法来解决由GC暂停引起的问题:切换垃圾收集器,调整控制Java堆的标志,进行代码更改以及使用替代的JVM /收集器。 以下是对HotSpot领域中考虑的方法及其解决的问题类型的快速概述:
1.错误的垃圾收集器正在运行
粗略地说,JVM有4个垃圾收集器,您可以选择在启动期间使用哪个垃圾收集器。 要了解有关每种类型的更多信息,可以在此处查看比较。 GC问题的常见原因之一是针对您正在开发的应用程序类型使用了错误的收集器。 HotSpot的默认值是并行/吞吐量收集器,通常它不是您的应用程序的最佳选择。 选择合适的收集器的行为(通过JVM标志)是对系统优先级的声明,通常是要考虑的第一个问题。 通常,大多数并发的CMS和G1收集器将导致较少的暂停时间。 尽管出现暂停时,其持续时间可能会比Parallel收集器引起的持续时间长,因为它们的后备机制是单线程的(Ouch)。 另一方面,对于相同大小的堆,并行收集器将实现更高的吞吐量。 另一个准则与可预测性有关,如果可预测的性能是一个重要因素并且堆大小不大,那么并行收集器可能就是答案。 并且,如果平均响应时间/延迟是您的重中之重,那么CMS或G1最有可能是答案。
2.调优Java堆
选择了首选的GC算法之后,该进行一些调整了。 测量(通过GC日志)吞吐量和暂停时间分布,如果对此感到满意,就可以完成。 如果GC开销很高(并且吞吐量很低),通常增加堆大小将改善这种情况。 当要解决CMS或G1的长时间停顿时,情况就更加棘手。 造成碎片化的另一个原因是,JVM无法跟上对象从新一代迁移到旧一代的速度,然后需要暂停应用程序对其进行修复。 解决方案是提早启动GC或增加堆大小。
从经验来看,堆大小通常在1GB到8GB之间,因此,更大的大小变得更为罕见。 在精简过程中,通常会在调整过程中将堆大小增加到8GB以上。 较大的堆大小的一个可行原因是,当我们想要创建一个大的缓存时,但这也可以在堆外解决。
让我们来看另一个示例,以显示需要调整溢出率的位置。 假设应用程序需要100MB的空间来处理某些请求,而新一代的大小为50MB。 不应该出现在旧一代中的对象将很快到达那里。 需要调整新世代和幸存者空间以解决此问题,并确保寿命短的物体将在新世代中终止其寿命。 影响这里的主要因素是堆大小,新旧发电比,幸存空间大小和最大使用期限阈值–对象移动到旧发电需要多少GC周期。
我们需要考虑的另一个重要因素是应用程序的“实时设置”。 意味着长时间保留在内存中的对象的大小,例如,活动集的示例将是一个应用缓存,其中包含频繁的数据库查询结果集。 在调整JVM时,需要确保“ liveset”可以方便地容纳在旧版本中,并且除了消耗之外,该区域还具有足够的可用内存。 否则,将严重破坏JVM的行为,从而导致低吞吐量和频繁的暂停。
3.架构和代码更改
一些问题将迫使我们诉诸代码,甚至可能进行体系结构更改。 我们这里可以解决的麻烦原因之一就是碎片化。 CMS收集器的长时间停顿可能是由旧一代的碎片导致的。 每个GC周期都会释放旧一代的内存块,使其看起来像瑞士奶酪,直到片刻JVM 不能处理它为止 。 当JVM将来自新一代的对象移动到比这些“漏洞”更大的对象上,然后必须停止应用程序来解决问题时,就会发生这种情况。 状态随时间变化的应用程序必然会导致碎片化。 随着状态随着时间的推移而变化,“旧状态”对象将从旧版本中释放,而它们的替换状态在新一代中创建。 当它最终晋升为老一代时,它可能会不适用于正确的地方,这将导致碎片化。
对这类问题的体系结构解决方案可能是更新对象,将“状态”移到堆外机制或拆分过程,对延迟敏感的关键路径,其中有许多短期分配的对象到一个进程,大状态到另一个进程一。
4.备用JVM和垃圾收集器
如果暂停时间对您的应用程序至关重要,并且Hotspot JVM无法提供可接受的响应时间,则还有两个可能的选择。 第一个是具有不间断C4垃圾收集器的Azul Zing JVM 。 为了开始使用Zing,您将需要具有相对较大的计算机,并且堆大小必须从32GB开始。 另一个尚不成熟的选择,但是如果您喜欢边缘化,可能值得一试的是Shenandoah GC算法。 它使用一种称为布鲁克转发指针的技术,该技术可导致超低的暂停时间和合理的开销。
进一步阅读:领先的GC专家
为了更深入地了解Garbage Collection和JVM的内部,下面是一些在GC领域最有趣的人:
- 查理·亨特 ( Charlie Hunt )是Oracle Java平台小组的成员,也是Java Performance一书的主要作者。
- C4不间断垃圾收集器的创建者Azul Systems的首席技术官兼联合创始人Gil Tene 。
- 性能调整和jClarity首席技术官兼联合创始人Kirk Pepperdine 。
- Monica Beckwitt ,Java / JVM性能顾问。
- Twitter的JVM / GC工程师Tony Printezis ,Oracle的前G1技术负责人。
- Oracle的JVM开发人员Jon Masamitsu 。
- Christine H. Flood和Roman Kennke ,Shenandoah GC算法的开发人员。
结论
垃圾回收是JVM中最引人入胜的主题之一,我们希望本文能帮助您更好地了解各个运动部件。 非常感谢Haim Yadid ,他同意与我们分享他的经验! 如果您有任何疑问或想要澄清,请在下面的评论部分中告诉我们。
java g1 收集调优