JVM从入门到入土之实战JVM调优(二)

简介: 前言文本已收录至我的GitHub仓库,欢迎Star:github.com/bin39232820…

絮叨


前面的章节

前面的章节

昨天我们做了一个基本的调优,但是你发现没有我们仅仅是说明了新生代的调优,今天我们就来看看老年代应该怎么来搞


前文回顾


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

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

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

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


此时的JVM参数如下所示


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


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

首先第一种情况,就是-XX:Max TenuringThreshold=5这个参数会让在一两分钟内连续躲过5次GC的对象,直接进入老年代

这种对象一般是@Service @Controller之类的注解标志的那种业务逻辑组件,

这种对象一般一个系统最多就是几十MB

所以此时长期存活对象就会进入老年代中,如下图所示

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


但是这种情况假设我们的场景没有,所以忽略不计

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

但是我们之前对新生代的优化,就是避免这种情况,但是也有可能刚好这么多,就进入了老年代了

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


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


接着我们来研究一下多久会触发Full GC ,

首先我们看Full GC触发的条件

  • 没有打开 -XX:HandlePromotionFailure选型,结果老年代可用内存最多也就1G,新生代你对象总大小最多是1.8G,那么会导致每次Mino GC前一检查,都发现老年代的可用内存<新生代总对象大小,这样会导致每次Minor GC前都触发Full GC 当然在JDK 1.6之后废弃了这个参数,其实只要看下面2个条件就好了
  • 每次Minor GC之前,都检查一下 老年代可用内存空间< 历代Minor GC后升入老年代的平均大小,其实按照我们的设定背景,要很多次的Minor GC 才有可能碰巧有200M的对象进入老年代,所以历代进入老年代的平均对象的大小,基本上是很小的
  • 可能某次Minor GC后要升入老年代的对象有几百M,但是老年代的可用空间不足了
  • 设置了 -XX:CMSInitiatingOccupancyFaction参数,比如设置了92%,那么此前几个条件可能没有满足,但是刚好总内存超过了92%,也会进行Full GC。

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

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

此时只要满足上述 2 3 4其中一个,就好触发Full GC

大家可以思考一下,我们假设再大促销期间,订单系统运行一小时之后,才触发Full GC,这种问题应该是不大的

因为这个是高峰期,如果是平时的话 几小时 才有可能一次Full GC 所以说这样的设计是可以的


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


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


但是有一个问题,就是CMS再垃圾回收的时候,尤其是并发清理期间,系统程序是可以并发进行的,所以老年代的空闲空间只剩下100M了

然后此时系统还在不停的创建对象,万一此时触发了一个条件,有200M要进入老年代,此时会怎么样呢?


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


但是这种概率是很低的的,我们就不用去理会了


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



在CMS完成Full GC之后,一般需要执行内存的碎片整理,可以设置多少次Full GC 之后执行一次对内存碎片的整理,但是我们能有必要去修改这些参数吗

其实没有必要,因为通过上面的分析,在大促销的高峰期,Full GC可能也就是1小时,然后高峰期过去,可能几小时才有一次Full GC

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

总结


其实对很多的普通的Java系统来说,只要对系统运行期间的内存的使用模型做好估计,然后分配好内存,尽量让Minor GC之后的存活对象在Survior不要去老年代,然后其余的参数不必要做过多的优化,系统基本上就不会太差


结尾


大家还是要自己多去尝试,自己去做过才有经验。

因为博主也是一个开发萌新 我也是一边学一边写 我有个目标就是一周 二到三篇 希望能坚持个一年吧 希望各位大佬多提意见,让我多学习,一起进步。

相关文章
|
12天前
|
Arthas 监控 Java
JVM进阶调优系列(9)大厂面试官:内存溢出几种?能否现场演示一下?| 面试就那点事
本文介绍了JVM内存溢出(OOM)的四种类型:堆内存、栈内存、元数据区和直接内存溢出。每种类型通过示例代码演示了如何触发OOM,并分析了其原因。文章还提供了如何使用JVM命令工具(如jmap、jhat、GCeasy、Arthas等)分析和定位内存溢出问题的方法。最后,强调了合理设置JVM参数和及时回收内存的重要性。
|
10天前
|
监控 Java 编译器
Java虚拟机调优实战指南####
本文深入探讨了Java虚拟机(JVM)的调优策略,旨在帮助开发者和系统管理员通过具体、实用的技巧提升Java应用的性能与稳定性。不同于传统摘要的概括性描述,本文摘要将直接列出五大核心调优要点,为读者提供快速预览: 1. **初始堆内存设置**:合理配置-Xms和-Xmx参数,避免频繁的内存分配与回收。 2. **垃圾收集器选择**:根据应用特性选择合适的GC策略,如G1 GC、ZGC等。 3. **线程优化**:调整线程栈大小及并发线程数,平衡资源利用率与响应速度。 4. **JIT编译器优化**:利用-XX:CompileThreshold等参数优化即时编译性能。 5. **监控与诊断工
|
21天前
|
存储 监控 Java
JVM进阶调优系列(8)如何手把手,逐行教她看懂GC日志?| IT男的专属浪漫
本文介绍了如何通过JVM参数打印GC日志,并通过示例代码展示了频繁YGC和FGC的场景。文章首先讲解了常见的GC日志参数,如`-XX:+PrintGCDetails`、`-XX:+PrintGCDateStamps`等,然后通过具体的JVM参数和代码示例,模拟了不同内存分配情况下的GC行为。最后,详细解析了GC日志的内容,帮助读者理解GC的执行过程和GC处理机制。
|
29天前
|
Arthas 监控 数据可视化
JVM进阶调优系列(7)JVM调优监控必备命令、工具集合|实用干货
本文介绍了JVM调优监控命令及其应用,包括JDK自带工具如jps、jinfo、jstat、jstack、jmap、jhat等,以及第三方工具如Arthas、GCeasy、MAT、GCViewer等。通过这些工具,可以有效监控和优化JVM性能,解决内存泄漏、线程死锁等问题,提高系统稳定性。文章还提供了详细的命令示例和应用场景,帮助读者更好地理解和使用这些工具。
|
1月前
|
监控 架构师 Java
JVM进阶调优系列(6)一文详解JVM参数与大厂实战调优模板推荐
本文详述了JVM参数的分类及使用方法,包括标准参数、非标准参数和不稳定参数的定义及其应用场景。特别介绍了JVM调优中的关键参数,如堆内存、垃圾回收器和GC日志等配置,并提供了大厂生产环境中常用的调优模板,帮助开发者优化Java应用程序的性能。
|
1月前
|
存储 监控 算法
JVM调优深度剖析:内存模型、垃圾收集、工具与实战
【10月更文挑战第9天】在Java开发领域,Java虚拟机(JVM)的性能调优是构建高性能、高并发系统不可或缺的一部分。作为一名资深架构师,深入理解JVM的内存模型、垃圾收集机制、调优工具及其实现原理,对于提升系统的整体性能和稳定性至关重要。本文将深入探讨这些内容,并提供针对单机几十万并发系统的JVM调优策略和Java代码示例。
51 2
|
1月前
|
Arthas 监控 Java
JVM知识体系学习七:了解JVM常用命令行参数、GC日志详解、调优三大方面(JVM规划和预调优、优化JVM环境、JVM运行出现的各种问题)、Arthas
这篇文章全面介绍了JVM的命令行参数、GC日志分析以及性能调优的各个方面,包括监控工具使用和实际案例分析。
46 3
|
1月前
|
算法 Java
JVM进阶调优系列(4)年轻代和老年代采用什么GC算法回收?
本文详细介绍了JVM中的GC算法,包括年轻代的复制算法和老年代的标记-整理算法。复制算法适用于年轻代,因其高效且能避免内存碎片;标记-整理算法则用于老年代,虽然效率较低,但能有效解决内存碎片问题。文章还解释了这两种算法的具体过程及其优缺点,并简要提及了其他GC算法。
 JVM进阶调优系列(4)年轻代和老年代采用什么GC算法回收?
|
1月前
|
Java
JVM进阶调优系列(5)CMS回收器通俗演义一文讲透FullGC
本文介绍了JVM中CMS垃圾回收器对Full GC的优化,包括Stop the world的影响、Full GC触发条件、GC过程的四个阶段(初始标记、并发标记、重新标记、并发清理)及并发清理期间的Concurrent mode failure处理,并简述了GC roots的概念及其在GC中的作用。
|
1月前
|
算法 Java
JVM进阶调优系列(3)堆内存的对象什么时候被回收?
堆对象的生命周期是咋样的?什么时候被回收,回收前又如何流转?具体又是被如何回收?今天重点讲对象GC,看完这篇就全都明白了。

相关实验场景

更多