JVM02——JVM垃圾回收与性能调优(下)(二)

简介: 6.垃圾回收6.1 判断垃圾6.1.1 引用计数法

(9)巨型对象


巨型对象指大小大于region的一半的对象,在jdk8u60后,可以回收巨型对象。


巨型对象有如下特别之处。


G1不会复制巨型对象

垃圾回收时优先回收

当某个巨型对象被老年代的incoming引用为0时,将会在新生代垃圾回收时被回收(参考下图)。

(10)动态调整阈值


并发标记必须在堆占满前完成,否则将退化为full gc(注:在新版本的jvm中,full gc已经不是前文所提到的单线程,但是仍然有很长的STW时间,需要避免)。在jdk9之前我们采用-XX:InitiatingHeapOccupancyPercent来设置开始并发标记的阈值,但是阈值如果设置过低则频繁GC,如果设置过高则易Full GC。jdk9中可以对于阈值进行动态调整。


jdk中还有很多对于垃圾回收器的改进。建议多读官网文档:Java Platform, Standard Edition HotSpot Virtual Machine Garbage Collection Tuning Guide, Release 16 (oracle.com)。


6.9 GC调优

6.9.1 预备知识

(1) 常用命令


jvm调优需要对于一些常用的内存设置参数熟悉,可以查阅oracle官网。或使用命令java -XX:+PrintFlagsFinal -version | findstr "GC"查看jvm中与GC相关的虚拟机参数。


查看的结果示例如下。

java version "16.0.2" 2021-07-20
Java(TM) SE Runtime Environment (build 16.0.2+7-67)
Java HotSpot(TM) 64-Bit Server VM (build 16.0.2+7-67, mixed mode, sharing)
    uintx AdaptiveSizeMajorGCDecayTimeScale        = 10                                        {product} {default}
     uint ConcGCThreads                            = 3                                         {product} {ergonomic}
     bool DisableExplicitGC                        = false                                     {product} {default}
     bool ExplicitGCInvokesConcurrent              = false                                     {product} {default}
    uintx G1MixedGCCountTarget                     = 8                                         {product} {default}
    uintx G1PeriodicGCInterval                     = 0                                      {manageable} {default}
     bool G1PeriodicGCInvokesConcurrent            = true                                      {product} {default}
   double G1PeriodicGCSystemLoadThreshold          = 0.000000                               {manageable} {default}
    uintx GCDrainStackTargetSize                   = 64                                        {product} {ergonomic}
    uintx GCHeapFreeLimit                          = 2                                         {product} {default}
    uintx GCLockerEdenExpansionPercent             = 5                                         {product} {default}
    uintx GCPauseIntervalMillis                    = 201                                       {product} {default}
    uintx GCTimeLimit                              = 98                                        {product} {default}
    uintx GCTimeRatio                              = 12                                        {product} {default}
     bool HeapDumpAfterFullGC                      = false                                  {manageable} {default}
     bool HeapDumpBeforeFullGC                     = false                                  {manageable} {default}
   size_t HeapSizePerGCThread                      = 43620760                                  {product} {default}
    uintx MaxGCMinorPauseMillis                    = 18446744073709551615                      {product} {default}
    uintx MaxGCPauseMillis                         = 200                                       {product} {default}
      int ParGCArrayScanChunk                      = 50                                        {product} {default}
    uintx ParallelGCBufferWastePct                 = 10                                        {product} {default}
     uint ParallelGCThreads                        = 13                                        {product} {default}
     bool PrintGC                                  = false                                     {product} {default}
     bool PrintGCDetails                           = false                                     {product} {default}
     bool ScavengeBeforeFullGC                     = false                                     {product} {default}
     bool UseAdaptiveSizeDecayMajorGCCost          = true                                      {product} {default}
     bool UseAdaptiveSizePolicyWithSystemGC        = false                                     {product} {default}
     bool UseDynamicNumberOfGCThreads              = true                                      {product} {default}
     bool UseG1GC                                  = true                                      {product} {ergonomic}
     bool UseGCOverheadLimit                       = true                                      {product} {default}
     bool UseMaximumCompactionOnSystemGC           = true                                      {product} {default}
     bool UseParallelGC                            = false                                     {product} {default}
     bool UseSerialGC                              = false                                     {product} {default}
     bool UseShenandoahGC                          = false                                     {product} {default}
     bool UseZGC                                   = false                                     {product} {default}

(2) 掌握常用工具

(3) 调优与代码、平台相关,无万能范式。


6.9.2 调优内容

(1)调优领域


内存

锁竞争

cpu占用

io

(2) 调优目标


高吞吐量(科学运算):ParrellelGC

还是低延迟(互联网项目):CMS、G1、ZGC

hotspot外的虚拟机:zing…

6.9.3 代码复核

查看full gc前后的内存占用,考虑以下几个问题。


数据量是不是太多?下面代码就会加载大量数据到堆内存中。

resultSet = statement.executeQuery("select * from xxx");
1

应该改为:

resultSet = statement.executeQuery("select * from xxx limit n");
1

数据表示太臃肿?

对象用到什么数据项查什么数据项

对象大小 Integer24byte ,int24byte

是否存在内存泄漏?如:

static Map map = new HashMap();
1

对长期存活的对象建议使用弱引用、软引用。


对于缓存类型的数据建议使用第三方缓存实现,如redis。


6.9.4 新生区内存调优

(1) 新生代的特点


对象分配极其廉价:使用TLAB,即Thread Local allocation buffer(参考:浅析java中的TLAB - 简书 (jianshu.com)),避免了线程竞争,提高了内存分配的效率。

对象的销毁代价小:采用复制算法整理内存,对于垃圾对象销毁代价小。

大部分对象朝生夕死,minor gc时间远低于full gc

由于新生代具有以上特点,对于新生代进行内存调优效果更明显,往往进行内存调优时先考虑新生代的内存调优。


(2) 设置新生代内存大小


参数-Xmn可以设置新生代大小。如果新生代设置过小,将会导致minor gc频繁发生,耗费stw时间。如果新生代设置过大,或将导致只发生Full GC,占用的时间同样会很高,Oracle官方推荐设置为25%-50%。根据经验,我们一般将新生代的内存空间设置为:所容纳的最大并发量 * 一次请求响应的数据量。这样一次请求响应完成后大部分的内存将可以被释放,可以有效的减少GC的触发次数。


6.9.5 幸存区调优

(1) 设置幸存区大小


幸存区要至少能够存放当前活跃(将被回收)的对象+即将晋升(不被回收)的对象,如果幸存区的对象容纳不下,当前活跃的对象可能会被晋升到老年代,这就使一个本来拥有较短生命周期的对象在Full GC时才会被垃圾回收。


(2)设置合理晋升阈值


通过参数``-XX:+PrintTenuringDistribution可以打印各个年龄的对象在内存中的占用,-XX:+MaxTenuringThreshold=threshold`调整晋升阈值。如果幸存区的晋升阈值设置过大,则需要晋升到老年代的对象可能不会被及时晋升。而新生代进行Minor GC时耗费时间主要发生在复制对象上,这就会导致STW时间变长。


6.9.6 老年代调优

以CMS为例。


CMS的老年代的内存要尽可能大,避免浮动垃圾又导致内存溢出,使老年代退化。一般先进行新生代调优,有必要再考虑老年代调优。如果没有发生Full GC,一般无需对老年代进行调优,如果发生了Full GC,可以观察发生Full GC时老年代的内存占用超过的阈值,将老年代内存大小调大1/41/3.另外也可以用`-XX:+CMSInitiatingOccupyFraction=percent`设置老年代垃圾回收的时机,一般推荐设置为内存占用75%80%时。


6.9.7 调优案例

Full GC和Minor GC特别频繁

考虑新生代内存设置过小,通过增加新生代内存大小,避免频繁触发Minor GC,以及将生命周期较短的对象带入老年代进而引发Full GC。


请求高峰期发生Full GC,单次占用时间特别长(CMS)

查看GC日志,查看到底时CMS各阶段耗费时间。CMS再重新标记时耗时最多,根据日志发现有1s。由于在重新标记阶段,不仅会扫描老年代的对象,还会扫描新生代的对象,并根据根可达算法进行扫描,考虑在业务高峰器,新生代对象较多。可以将CMS重新标记前先将新生代内存进行一次整理。


在这里插入图片描述


老年代充足情况发生Full GC(CMS,jdk1.7)

查看输出提示信息并无并发失败、晋升失败等,说明老年代空间充裕,确认jdk版本为1.7,非jdk1.8。在jdk1.7及以前,方法区由元空间来管理,考虑元空间不足导致Full GC。

相关文章
|
4天前
|
监控 算法 Java
Java虚拟机(JVM)的垃圾回收机制深度解析####
本文深入探讨了Java虚拟机(JVM)的垃圾回收机制,旨在揭示其背后的工作原理与优化策略。我们将从垃圾回收的基本概念入手,逐步剖析标记-清除、复制算法、标记-整理等主流垃圾回收算法的原理与实现细节。通过对比不同算法的优缺点及适用场景,为开发者提供优化Java应用性能与内存管理的实践指南。 ####
|
18天前
|
算法 JavaScript 前端开发
垃圾回收机制对 JavaScript 性能的影响有哪些?
【10月更文挑战第29天】垃圾回收机制对JavaScript性能有着重要的影响。开发者需要了解不同垃圾回收算法的特点和性能开销,通过合理的代码优化和内存管理策略,来降低垃圾回收对性能的负面影响,提高JavaScript程序的整体性能。
|
12天前
|
Arthas 监控 Java
JVM进阶调优系列(9)大厂面试官:内存溢出几种?能否现场演示一下?| 面试就那点事
本文介绍了JVM内存溢出(OOM)的四种类型:堆内存、栈内存、元数据区和直接内存溢出。每种类型通过示例代码演示了如何触发OOM,并分析了其原因。文章还提供了如何使用JVM命令工具(如jmap、jhat、GCeasy、Arthas等)分析和定位内存溢出问题的方法。最后,强调了合理设置JVM参数和及时回收内存的重要性。
|
14天前
|
缓存 算法 Java
本文聚焦于Java内存管理与调优,介绍Java内存模型、内存泄漏检测与预防、高效字符串拼接、数据结构优化及垃圾回收机制
在现代软件开发中,性能优化至关重要。本文聚焦于Java内存管理与调优,介绍Java内存模型、内存泄漏检测与预防、高效字符串拼接、数据结构优化及垃圾回收机制。通过调整垃圾回收器参数、优化堆大小与布局、使用对象池和缓存技术,开发者可显著提升应用性能和稳定性。
36 6
|
10天前
|
监控 Java 编译器
Java虚拟机调优实战指南####
本文深入探讨了Java虚拟机(JVM)的调优策略,旨在帮助开发者和系统管理员通过具体、实用的技巧提升Java应用的性能与稳定性。不同于传统摘要的概括性描述,本文摘要将直接列出五大核心调优要点,为读者提供快速预览: 1. **初始堆内存设置**:合理配置-Xms和-Xmx参数,避免频繁的内存分配与回收。 2. **垃圾收集器选择**:根据应用特性选择合适的GC策略,如G1 GC、ZGC等。 3. **线程优化**:调整线程栈大小及并发线程数,平衡资源利用率与响应速度。 4. **JIT编译器优化**:利用-XX:CompileThreshold等参数优化即时编译性能。 5. **监控与诊断工
|
1月前
|
缓存 算法 Java
JVM知识体系学习六:JVM垃圾是什么、GC常用垃圾清除算法、堆内存逻辑分区、栈上分配、对象何时进入老年代、有关老年代新生代的两个问题、常见的垃圾回收器、CMS
这篇文章详细介绍了Java虚拟机(JVM)中的垃圾回收机制,包括垃圾的定义、垃圾回收算法、堆内存的逻辑分区、对象的内存分配和回收过程,以及不同垃圾回收器的工作原理和参数设置。
66 4
JVM知识体系学习六:JVM垃圾是什么、GC常用垃圾清除算法、堆内存逻辑分区、栈上分配、对象何时进入老年代、有关老年代新生代的两个问题、常见的垃圾回收器、CMS
|
1月前
|
存储 监控 算法
美团面试:说说 G1垃圾回收 底层原理?说说你 JVM 调优的过程 ?
尼恩提示: G1垃圾回收 原理非常重要, 是面试的重点, 大家一定要好好掌握
美团面试:说说 G1垃圾回收 底层原理?说说你 JVM 调优的过程  ?
|
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应用程序的性能。