jvm性能调优 - 17案例实战_每日上亿请求量的电商系统 老轻代垃圾回收参数如何优化

简介: jvm性能调优 - 17案例实战_每日上亿请求量的电商系统 老轻代垃圾回收参数如何优化

Pre

上一篇文章我们已经给大家介绍了一个每日百万日活以及上亿请求量的电商系统的案例背景,同时采用这个中型电商系统在大促期间的瞬时高峰下单场景,作为我们的JVM优化分析的一个场景,推测出来在大促高峰期,每秒每台机器会有300个下单请求。

进而推测出每秒钟会使用60MB的内存,然后根据这个背景推算出来了我们一台4核8G的机器上,应该如何合理的给JVM各个区域分配内存

进而可以保证每隔20多秒一次新生代GC后的100MB左右的存活对象,会进入200MB的Survivor区域内,一般不会因为Survivor塞不下或者是动态年龄判定规则让对象进入老年代中。

同时还根据Minor GC的频率,合理降低了大龄对象进入老年代的年龄,尽快让一些长期存活的对象赶紧进入老年代,不要停留在新生代里,如下图所示。

此时的JVM参数如下所示:

-Xms3072M -Xmx3072M -Xmn2048M -Xss1M  -XX:PermSize=256M -XX:MaxPermSize=256M  -XX:SurvivorRatio=8 -XX:MaxTenuringThreshold=5 -XX:PretenureSizeThreshold=1M -XX:+UseParNewGC -XX:+UseConcMarkSweepGC

在案例背景下什么时候对象会进入老年代?

接着我们来分析一个问题,在目前优化好的背景下,一般什么情况下会让一些对象进入老年代呢?

首先第一种情况,那绝对就是“-XX:MaxTenuringThreshold=5”这个参数会让在一两分钟内连续躲过5次Minor GC的对象迅速进入老年代中。

这种对象一般就是一些@Service、@Controller之类的注解标注的那种系统业务逻辑组件,这种对象实例一般全局就有一个实例就可以了,要一直使用的

所以一般会长期被GC Roots引用,这种对象一般不会太多,大概最多一个系统就几十MB这种对象。

所以此时类似这样的长期存活的对象就会进入老年代中,如下图所示。

此外,按照我们的JVM参数,如果分配一个超过1MB的大对象,比如说你创建一个大数组或者是大List之类的,就会直接进入老年代。

但是这种大对象我们假设在这个案例里是没有的,所以可以忽略不计。

此外就是Minor GC过后可能存活的对象超过200MB放不下Survivor了,或者是一下子占到超过Surviovr的50%,此时会有一些对象进入老年代中。

但是我们之前对新生代的JVM参数进行优化,就是为了避免这种情况,经过我们的测算,这种概率应该是很低的。

但是虽说是很低,也不能完全是是没有这种情况,比如某一次GC过后可能刚好机缘巧合有超过200MB对象,就会进入老年代里。

我们可以做一个假设,大概就是这个订单系统在大促期间,每隔5分钟会在Minor GC之后有一小批对象进入老年代,大概200MB左右的大小,如下图所示。


大促期间多久会触发一次Full GC?

接着我们来研究一下,那么按照Full GC的触发条件,多久会触发一次Full GC?

首先来看看,Full GC的触发条件目前我们学习到的有以下4种:

  • 没有打开“ -XX:HandlePromotionFailure”选项,结果老年代可用内存最多也就1G,新生代对象总大小最多可以有1.8G . 那么会导致每次Minor GC前一检查,都发现“老年代可用内存” < “新生代总对象大小”,这会导致每次Minor GC前都触发Full GC。

现在JDK 1.6以后的版本废弃了这个参数,其实只要满足下面第二个条件就可以直接触发Minor GC,不需要触发Full GC。

  • 每次Minor GC之前,都检查一下“老年代可用内存空间” < “历次Minor GC后升入老年代的平均对象大小”

其实按照我们目前设定的背景,要很多次Minor GC之后才可能有一两次碰巧会有200MB对象升入老年代,所以这个“历次Minor GC后升入老年代的平均对象大小”,基本是很小的。

  • 可能某次Minor GC后要升入老年代的对象有几百MB,但是老年代可用空间不足了
  • 设置了“-XX:CMSInitiatingOccupancyFaction”参数,比如设定值为92%,那么此时可能前面几个条件都没满足,但是刚好发现这个条件满足了,比如就是老年代空间使用超过92%了,此时就会自行触发Full GC

其实在真正的系统运行期间,可能会慢慢的有对象进入老年代,但是因为新生代我们优化过了内存分配,所以对象进入老年代的速度是很慢的。

所以很可能是在系统运行半小时~1小时之后,才会有接近 1GB的对象进入老年代。

此时可能会因为上述的条件234中任何一个满足了,就触发Full GC。

但是这三个条件一般都需要老年代近乎占满的时候,才有可能会触发。

大家可以思考一下,我们假设在大促期间,订单系统运行1小时之后,大促下单高峰期几乎都快过了,此时才可能会触发一次Full GC。

注意,这个推论很重要,因为按照大促开始10分钟就有50万订单来计算,其实大促开始后一堆用户等着下单剁手购物

那么1小时候就可能有两三百万订单了,这是一年难得罕见的节日大促才会有的,然后这个高峰期过后,基本订单系统访问压力就很小了,那么GC的问题几乎就更不算什么了。

所以经过新生代的优化,可以推算出,基本上大促高峰期内,也就可能1小时才1次Full GC,然后高峰期一过,随着订单系统慢慢运行,可能就要几个小时才有一次Full GC。


老年代GC的时候会发生“Concurrent Mode Failure”吗?

经过前面的推算,我们基本可知道,假设就是订单系统运行1小时之后,老年代大概有900MB的对象了,剩余可用空间仅仅只有100MB了,此时就会触发一次Full GC,如下图。

但是有一个很大的问题,就是CMS在垃圾回收的时候,尤其是并发清理期间,系统程序是可以并发运行的,所以此时老年代空闲空间仅剩100MB了

然后此时系统程序还在不停的创建对象,万一这个时候系统运行触发了某个条件,比如说有200MB对象要进入老年代,此时会如何?

如下图

这个时候就会触发“Concurrent Mode Failure”问题,因为此时老年代没有足够内存来放这200MB对象,此时就会导致立马进入Stop the World,然后切换CMS为Serial Old,直接禁止程序运行,然后单线程进行老年代垃圾回收,回收掉900MB对象过后,再让系统继续运行,如下图。

所以可以想一下,这种情况可能发生吗?

概率是挺小的,因为必须是CMS触发Full GC的时候,系统运行期间还让200MB对象进入老年代,这个概率其实本身就很小,但是理论上是有可能的。

大家此时需要思考一下,相对于这种小概率的事件而言,有必要去调整参数吗?

暂时看来是没有必要的,不需要针对小概率事件特意优化参数。

此时JVM参数如下:

“-Xms3072M -Xmx3072M -Xmn2048M -Xss1M  -XX:PermSize=256M -XX:MaxPermSize=256M  -XX:SurvivorRatio=8 -XX:MaxTenuringThreshold=5 -XX:PretenureSizeThreshold=1M -XX:+UseParNewGC -XX:+UseConcMarkSweepGC -XX:CMSInitiatingOccupancyFaction=92”

CMS垃圾回收之后进行内存碎片整理的频率应该多高?

接着来看最后一个问题,在CMS完成Full GC之后,一般需要执行内存碎片的整理,可以设置多少次Full GC之后执行一次内存碎片整理,但是我们有必要修改这些参数吗?

其实没必要,因为通过前面的分析,在大促高峰期,Full GC可能也就1小时执行一次,然后大促高峰期过去之后,就没那么多的订单了,此时可能几个小时才会有一次Full GC。

所以就保持默认的设置,每次Full GC之后都执行一次内存碎片整理就可以,目前JVM参数如下:

“-Xms3072M -Xmx3072M -Xmn2048M -Xss1M  -XX:PermSize=256M -XX:MaxPermSize=256M  -XX:SurvivorRatio=8 -XX:MaxTenuringThreshold=5 -XX:PretenureSizeThreshold=1M -XX:+UseParNewGC -XX:+UseConcMarkSweepGC -XX:CMSInitiatingOccupancyFaction=92 -XX:+UseCMSCompactAtFullCollection -XX:CMSFullGCsBeforeCompaction=0”

其实从本文可以看到,Full GC优化的前提是Minor GC的优化,Minor GC的优化的前提是合理分配内存空间,合理分配内存空间的前提是对系统运行期间的内存使用模型进行预估。

其实对很多普通的Java系统而言,只要对系统运行期间的内存使用模型做好预估,然后分配好合理的内存空间,尽量让Minor GC之后的存活对象留在Survivor里不要去老年代,然后其余的GC参数不做太多优化,系统性能基本上就不会太差。


相关文章
|
20天前
|
监控 算法 Java
Java虚拟机(JVM)垃圾回收机制深度剖析与优化策略####
本文作为一篇技术性文章,深入探讨了Java虚拟机(JVM)中垃圾回收的工作原理,详细分析了标记-清除、复制算法、标记-压缩及分代收集等主流垃圾回收算法的特点和适用场景。通过实际案例,展示了不同GC(Garbage Collector)算法在应用中的表现差异,并针对大型应用提出了一系列优化策略,包括选择合适的GC算法、调整堆内存大小、并行与并发GC调优等,旨在帮助开发者更好地理解和优化Java应用的性能。 ####
25 0
|
19天前
|
存储 监控 算法
Java虚拟机(JVM)垃圾回收机制深度解析与优化策略####
本文旨在深入探讨Java虚拟机(JVM)的垃圾回收机制,揭示其工作原理、常见算法及参数调优方法。通过剖析垃圾回收的生命周期、内存区域划分以及GC日志分析,为开发者提供一套实用的JVM垃圾回收优化指南,助力提升Java应用的性能与稳定性。 ####
|
23天前
|
机器学习/深度学习 监控 算法
Java虚拟机(JVM)的垃圾回收机制深度剖析####
本文深入探讨Java虚拟机(JVM)的垃圾回收机制,揭示其工作原理、常见算法、性能调优策略及未来趋势。通过实例解析,为开发者提供优化Java应用性能的思路与方法。 ####
32 1
|
26天前
|
监控 算法 Java
Java虚拟机垃圾回收机制深度剖析与优化策略####
【10月更文挑战第21天】 本文旨在深入探讨Java虚拟机(JVM)中的垃圾回收机制,揭示其工作原理、常见算法及参数调优技巧。通过案例分析,展示如何根据应用特性调整GC策略,以提升Java应用的性能和稳定性,为开发者提供实战中的优化指南。 ####
40 5
|
26天前
|
存储 算法 Java
JVM进阶调优系列(10)敢向stop the world喊卡的G1垃圾回收器 | 有必要讲透
本文详细介绍了G1垃圾回收器的背景、核心原理及其回收过程。G1,即Garbage First,旨在通过将堆内存划分为多个Region来实现低延时的垃圾回收,每个Region可以根据其垃圾回收的价值被优先回收。文章还探讨了G1的Young GC、Mixed GC以及Full GC的具体流程,并列出了G1回收器的核心参数配置,帮助读者更好地理解和优化G1的使用。
|
24天前
|
存储 IDE Java
实战优化公司线上系统JVM:从基础到高级
【11月更文挑战第28天】Java虚拟机(JVM)是Java语言的核心组件,它使得Java程序能够实现“一次编写,到处运行”的跨平台特性。在现代应用程序中,JVM的性能和稳定性直接影响到系统的整体表现。本文将深入探讨JVM的基础知识、基本特点、定义、发展历史、主要概念、调试工具、内存管理、垃圾回收、性能调优等方面,并提供一个实际的问题demo,使用IntelliJ IDEA工具进行调试演示。
26 0
|
26天前
|
算法 Java
JVM有哪些垃圾回收算法?
(1)标记清除算法: 标记不需要回收的对象,然后清除没有标记的对象,会造成许多内存碎片。 (2)复制算法: 将内存分为两块,只使用一块,进行垃圾回收时,先将存活的对象复制到另一块区域,然后清空之前的区域。用在新生代 (3)标记整理算法: 与标记清除算法类似,但是在标记之后,将存活对象向一端移动,然后清除边界外的垃圾对象。用在老年代
22 0
|
2月前
|
缓存 算法 Java
JVM知识体系学习六:JVM垃圾是什么、GC常用垃圾清除算法、堆内存逻辑分区、栈上分配、对象何时进入老年代、有关老年代新生代的两个问题、常见的垃圾回收器、CMS
这篇文章详细介绍了Java虚拟机(JVM)中的垃圾回收机制,包括垃圾的定义、垃圾回收算法、堆内存的逻辑分区、对象的内存分配和回收过程,以及不同垃圾回收器的工作原理和参数设置。
79 4
JVM知识体系学习六:JVM垃圾是什么、GC常用垃圾清除算法、堆内存逻辑分区、栈上分配、对象何时进入老年代、有关老年代新生代的两个问题、常见的垃圾回收器、CMS
|
3月前
|
监控 算法 Java
深入理解Java中的垃圾回收机制在Java编程中,垃圾回收(Garbage Collection, GC)是一个核心概念,它自动管理内存,帮助开发者避免内存泄漏和溢出问题。本文将探讨Java中的垃圾回收机制,包括其基本原理、不同类型的垃圾收集器以及如何调优垃圾回收性能。通过深入浅出的方式,让读者对Java的垃圾回收有一个全面的认识。
本文详细介绍了Java中的垃圾回收机制,从基本原理到不同类型垃圾收集器的工作原理,再到实际调优策略。通过通俗易懂的语言和条理清晰的解释,帮助读者更好地理解和应用Java的垃圾回收技术,从而编写出更高效、稳定的Java应用程序。
|
2月前
|
存储 Java PHP
【JVM】垃圾回收机制(GC)之引用计数和可达性分析
【JVM】垃圾回收机制(GC)之引用计数和可达性分析
84 0