深入了解JVM调优:解锁Java应用程序性能的秘诀

简介: 深入了解JVM调优:解锁Java应用程序性能的秘诀


🍊 JVM调优

JVM调优情况十分复杂,各种情况都可能导致垃圾回收不能够达到预想的效果。对于场景问题,可以从如下几个大方向进行设计:

🎉 增大Eden 空间大小

大访问压力下,MGC 频繁一些是正常的,只要MGC 延迟不导致停顿时间过长或者引发FGC ,那可以适当的增大Eden 空间大小,降低频繁程度,同时要保证,空间增大对垃圾回收产生的停顿时间增长是可以接受的。

🎉 如果MinorGC 频繁,且容易引发 Full GC

需要从如下几个角度进行分析。

📝 S1 区大小 < MGC 存活的对象大小,对象的年龄才1岁

每次MGC存活的对象的大小,是否能够全部移动到 S1区,如果S1 区大小 < MGC 存活的对象大小,这批对象会直接进入老年代。注意 了,这批对象的年龄才1岁,很有可能再多等1次MGC 就能被回收了,可是却进入了老年代,只能等到Full GC 进行回收,很可怕。这种情况下,应该在系统压测的情况下,实时监控MGC存活的对象大小,并合理调整eden和s 区的大小以及比例。

📝 相同年龄的对象所占总空间大小>s1区空间大小的一半

还有一种情况会导致对象在未达到15岁之前,直接进入老年代,就是S1区的对象,相同年龄的对象所占总空间大小>s1区空间大小的一半,所以为了应对这种情况,对于S区的大小的调整就要考虑:尽量保证峰值状态下,S1区的对象所占空间能够在MGC的过程中,相同对象年龄所占空间不大于S1区空间的一半, 因此对于S1空间大小的调整,也是十分重要的。

📝 解决方案
🔥 调整年龄阈值

可以通过设置 JVM 参数"-XX:MaxTenuringThreshold"来调整年龄阈值。该参数指定对象晋升老年代的最大年龄,通常默认值为15岁。可以逐渐增加该值,以减少老年代中相同年龄对象的数量。

请注意,调整年龄阈值需要根据具体应用程序的情况来确定。如果将年龄阈值设置得太高,可能会导致年轻代中的对象数量过多,从而增加Young GC的频率,进而影响系统性能。

🔥 增加S区的大小

如果S区足够大,那么S1区所占的比例就会更小。这样可以降低相同年龄段对象的总空间大小,从而使其不大于S1区的一半。

🔥 改变对象分配的位置
  • 设置对象的大小阈值。通过调整对象分配的大小阈值,可以让 JVM 将较大的对象分配到老年代中,减少新生代中对象数量,从而减少垃圾回收的频率。可以通过 -XX:PretenureSizeThreshold 参数来设置对象的大小阈值。
  • 调节新生代大小。通过调整新生代的大小,可以增加对象在新生代中的寿命,从而让更多的对象进入老年代,减少在新生代中对象的数量。可以通过调整 -Xmn 参数来设置新生代的大小。
  • 调节垃圾回收器参数。不同的垃圾回收器有不同的参数,可以根据具体的情况调节垃圾回收器的参数,以达到更好的效果。比如使用 G1 垃圾回收器,可以通过调节 -XX:G1HeapRegionSize 参数来控制 region 的大小,从而控制对象在不同 region 中的分配情况。

🎉 大对象创建频繁

由于大对象创建频繁,导致Full GC 频繁。对于大对象,JVM专门有参数进行控制,-XX: PretenureSizeThreshold。超过这个参数值的对象,会直接进入老年代,只能等到full GC 进行回收,所以在系统压测过程中,要重点监测大对象的产生。如果能够优化对象大小,则进行代码层面的优化,优化如:根据业务需求看是否可以将该大对象设置为单例模式下的对象,或者该大对象是否可以进行拆分使用,或者如果大对象确定使用完成后,将该对象赋值为null,方便垃圾回收。

📝 代码层面无法优化

如果代码层面无法优化,则需要考虑:

🔥 调高-XX: PretenureSizeThreshold参数的大小

调高-XX: PretenureSizeThreshold参数的大小,使对象有机会在eden区创建,有机会经历MGC以被回收。但是这个参数的调整要结合MGC过程中Eden区的大小是否能够承载,包括S1区的大小承载问题。

🔥 大对象必须进入老年代

这是最不希望发生的情况, 如果必须要进入老年代,也要尽量保证,该对象确实是长时间使用的对象,放入老年代的总对象创建量不会造成老年代的内存空间迅速长满发生Full GC,在这种情况下,可以通过定时脚本,在业务系统不繁忙情况下,主动触发full gc。

🎉 MGC 与 FGC 停顿时间长

MGC 与 FGC 停顿时间长导致影响用户体验。其实对于停顿时间长的问题无非就两种情况:

📝 gc 真实回收过程时间长

gc 真实回收过程时间长,即real time时间长。这种时间长大部分是因为内存过大导致,从标记到清理的过程中需要对很大的空间进行操作,导致停顿时间长。这种情况,要考虑减少堆内存大 小,包括新生代和老年代,比如之前使用16G的堆内存,可以考虑将16G 内存拆分为4个4G的内存区域,可以单台机器部署JVM逻辑集群,也可以为了降低GC回收时间,进行4节点的分布式部署,这里的分布式部署是为了降低 GC垃圾回收时间。

📝 gc真实回收时间 real time 并不长

gc真实回收时间 real time 并不长,但是user time(用户态执行时间) 和 sys time(核心态执行时间)时间长,导致从客户角度来看,停顿时间过长。这种情况,要考虑线程是否及时达到了安全点,通过-XX:+PrintSafepointStatistics和-XX: PrintSafepointStatisticsCount=1去查看安全点日志,如果有长时间未达到安全点的线程,再通过参数-XX: +SafepointTimeout和-XX:SafepointTimeoutDelay=2000两个参数来找到大于2000ms到达安全点的线程,这里 的2000ms可以根据情况自己设置,然后对代码进行针对的调整。除了安全点问题,也有可能是操作系统本身负载比较高,导致处理速度过慢,线程达到安全点时间长,因此需要同时检测操作系统自身的运行情况。

🎉 内存泄漏导致的MGC和FGC频繁,最终引发oom

纯代码级别导致的MGC和FGC频繁。如果是这种情况,那就只能对代码进行大范围的调整,这种情况就非常多了,而且会很糟糕。如大循环体中的new 对象,未使用合理容器进行对象托管导致对象创建频繁,不合理的数据结构使用等等。 总之,JVM的调优无非就一个目的,在系统可接受的情况下达到一个合理的MGC和FGC的频率以及可接受的回收时间。

🎉 JVM调优步骤

📝 1. 收集数据

使用命令或GUI工具收集JVM内存和处理器使用信息,并生成堆转储快照。

📝 2. 分析数据

使用工具分析收集到的数据,计算GC吞吐量和新生代大小等,分析堆中对象的分布情况,查看是否有内存泄漏等问题。

📝 3. 制定优化方案

根据分析的数据确定具体的优化方案,比如调整内存大小、垃圾回收机制、优化代码等。尝试调整GC算法、分配大对象空间、增加GC并行度等进行GC调优,尝试减少对象的创建、复用对象等进行内存调优。

📝 4. 验证优化效果

使用性能测试工具进行压力测试,验证优化效果是否符合预期。

📝 5. 持续监控

持续监控应用程序,及时发现并解决新问题,进行JVM调优。


相关文章
|
5天前
|
XML Java 数据库连接
性能提升秘籍:如何高效使用Java连接池管理数据库连接
在Java应用中,数据库连接管理至关重要。随着访问量增加,频繁创建和关闭连接会影响性能。为此,Java连接池技术应运而生,如HikariCP。本文通过代码示例介绍如何引入HikariCP依赖、配置连接池参数及使用连接池高效管理数据库连接,提升系统性能。
27 5
|
7天前
|
JSON Java Apache
非常实用的Http应用框架,杜绝Java Http 接口对接繁琐编程
UniHttp 是一个声明式的 HTTP 接口对接框架,帮助开发者快速对接第三方 HTTP 接口。通过 @HttpApi 注解定义接口,使用 @GetHttpInterface 和 @PostHttpInterface 等注解配置请求方法和参数。支持自定义代理逻辑、全局请求参数、错误处理和连接池配置,提高代码的内聚性和可读性。
|
16天前
|
人工智能 前端开发 Java
基于开源框架Spring AI Alibaba快速构建Java应用
本文旨在帮助开发者快速掌握并应用 Spring AI Alibaba,提升基于 Java 的大模型应用开发效率和安全性。
基于开源框架Spring AI Alibaba快速构建Java应用
|
9天前
|
SQL 安全 Java
安全问题已经成为软件开发中不可忽视的重要议题。对于使用Java语言开发的应用程序来说,安全性更是至关重要
在当今网络环境下,Java应用的安全性至关重要。本文深入探讨了Java安全编程的最佳实践,包括代码审查、输入验证、输出编码、访问控制和加密技术等,帮助开发者构建安全可靠的应用。通过掌握相关技术和工具,开发者可以有效防范安全威胁,确保应用的安全性。
23 4
|
9天前
|
SQL Java 数据库连接
从理论到实践:Hibernate与JPA在Java项目中的实际应用
本文介绍了Java持久层框架Hibernate和JPA的基本概念及其在具体项目中的应用。通过一个在线书店系统的实例,展示了如何使用@Entity注解定义实体类、通过Spring Data JPA定义仓库接口、在服务层调用方法进行数据库操作,以及使用JPQL编写自定义查询和管理事务。这些技术不仅简化了数据库操作,还显著提升了开发效率。
22 3
|
19天前
|
SQL 监控 Java
技术前沿:Java连接池技术的最新发展与应用
本文探讨了Java连接池技术的最新发展与应用,包括高性能与低延迟、智能化管理和监控、扩展性与兼容性等方面。同时,结合最佳实践,介绍了如何选择合适的连接池库、合理配置参数、使用监控工具及优化数据库操作,为开发者提供了一份详尽的技术指南。
29 7
|
17天前
|
SQL Java 数据库连接
在Java应用中,数据库访问常成为性能瓶颈。连接池技术通过预建立并复用数据库连接,有效减少连接开销,提升访问效率
在Java应用中,数据库访问常成为性能瓶颈。连接池技术通过预建立并复用数据库连接,有效减少连接开销,提升访问效率。本文介绍了连接池的工作原理、优势及实现方法,并提供了HikariCP的示例代码。
31 3
|
17天前
|
存储 Java 关系型数据库
在Java开发中,数据库连接是应用与数据交互的关键环节。本文通过案例分析,深入探讨Java连接池的原理与最佳实践
在Java开发中,数据库连接是应用与数据交互的关键环节。本文通过案例分析,深入探讨Java连接池的原理与最佳实践,包括连接创建、分配、复用和释放等操作,并通过电商应用实例展示了如何选择合适的连接池库(如HikariCP)和配置参数,实现高效、稳定的数据库连接管理。
34 2
|
19天前
|
Java 数据库连接 数据库
优化之路:Java连接池技术助力数据库性能飞跃
在Java应用开发中,数据库操作常成为性能瓶颈。频繁的数据库连接建立和断开增加了系统开销,导致性能下降。本文通过问题解答形式,深入探讨Java连接池技术如何通过复用数据库连接,显著减少连接开销,提升系统性能。文章详细介绍了连接池的优势、选择标准、使用方法及优化策略,帮助开发者实现数据库性能的飞跃。
25 4
|
17天前
|
Java 数据库连接 数据库
深入探讨Java连接池技术如何通过复用数据库连接、减少连接建立和断开的开销,从而显著提升系统性能
在Java应用开发中,数据库操作常成为性能瓶颈。本文通过问题解答形式,深入探讨Java连接池技术如何通过复用数据库连接、减少连接建立和断开的开销,从而显著提升系统性能。文章介绍了连接池的优势、选择和使用方法,以及优化配置的技巧。
16 1