Java实战指南|通过GC性能指标来优化你的Java程序

418 阅读5分钟

这是我参与更文挑战的第23天,活动详情查看: 更文挑战

前言:

随着业务的迭代,请求量的增大,我们会发现系统吞吐量逐渐的进入瓶颈,高峰时期会因为一些原因我们系统会出现一系列的问题,例如响应变慢,请求失败,甚至服务会直接被打挂,当你的系统到这个地步的时候,这个时候就还考虑如何优化你的项目(当然最直接的还是“加机器”)当对java应用的内存和GC调优时,我们应该基于关键性能指标来做决定,哪些我们应该着重考虑呢?我们今天主要讲一些我们在优化项目的时候通过那些指标来观察你的项目,以此来锁定你的优化点,这也是小编最近一直在做的事情,这里给大家写一些心德体会;

GC性能指标:

  1. 吞吐量:应用花在非GC上的时间百分比
  2. GC负荷:与吞吐量相反,指应用花在GC上的时间百分比
  3. 暂停时间:应用花在GC stop-the-world的时间如果你负责的服务要求是任何请求不超过5秒,那么你的最大GC停顿时长就不能超过5秒。因为在GC停顿时,整个JVM会暂停,任何业务代码都无法执行,因此所以最大GC停顿时间很重要;
  4. GC频率 反应速度:从一个对象变成垃圾到这个对象被回收的时间一个交互式的应用要求暂停时间越少越好,然而,一个非交互性的应用,当然是希望GC负荷越低越好;

内存容量配置选择

年轻代:

  • 响应时间优先的应用:尽可能设大,直接接近系统的最低响应时间限制(根据实际情况选择),在此种情况下,年轻代GC发生的频率也是最小的,同时,减少到达老年代的对象。
  • 吞吐量优先的应用:尽可能的设置大,可能达到Gbit的程度,因为响应时间没有要求,垃圾收集可以并行进行,一般8CPU以上的应用避免设置过小,当新生代设置过小时会导致YGC次数更加频繁,可能导致YGC对象直接进入老年代,如果此时老年代满了,会触发FGC;

老年代

  • 响应时间优先的应用:老年代使用并发收集器,所以其大小需要小心设置,一般要考虑并发会话率和会话持续时间等一些参数,如果堆设置小了,可能会造成内存碎片,高回收频率以及应用暂停而使用传统的标记清除方式;如果堆大了,则需要较长的收集时间,最优化的方案,一般需要参考一些其他的数据获得:并发垃圾收集信息持久代并发收集次数传统GC信息花在年轻代和老年代回收上的时间比例

  • 吞吐量优先的应用:一般吞吐量优先的应用都有一个很大的年轻代和一个较小的老年代,原因是:可以尽可能回收掉大部分短期对象,减少中期的对象而老年代尽存放长期存活对象;

GC开销还会使吞吐量急剧下降,进而使得应用难以形容的慢.此外,及早调整GC可以帮助你避免堆大小分配的问题.开始的时候,你可以选择任何1GB到8GB的堆大小.当你选择正确的堆大小,老生代和新生代对象的概念也就不需要了.总而言之,堆大小应该取决于老生代和新生代对象的比率,之前的GC优化和对象集合(即所有对象占用的内存大小).

根据内存调优准则,对于吞吐量,延迟,CPU,你最多只能三者取其二

  • 如果你想要比较好的吞吐量和延迟,那就得在CPU消耗上有所牺牲
  • 如果你想要比较好的吞吐量和CPU消耗,那就得在延迟上有所牺牲
  • 如果你想要比较好的延迟和CPU消耗,那就得在吞吐量上有所牺牲

关键应用优化

除了对内存配比进行优化为其实我们很多的时候都是对关键代码进行优化,例如小编的系统是每隔10分钟便会出现YGC频率特别高,而且会出现一些断崖式的回收,原因是我们的代码中每10分钟会有多个定时任务去做一些创建大量对象的任务;所以导致每次到任务执行的时候频繁发生YGC,导致系统在那个时候会变慢; 这个是我的YGC和GC停顿时间图 图片.png

图片.png

这个时候就需要优化你的代码了,可以根据自身业务条件去调整;

ok!今天的文章就到这了,希望可以对大家有帮助,有不对的地方希望大家可以提出来的,共同成长;

整洁成就卓越代码,细节之中只有天地