【JVM性能调优】- 年老代-提升速率

一、JVM垃圾收集相关调优策略

   在JVM垃圾收集相关的调优实践中,通常都是以最优吞吐量和最短停顿时间来评价JVM的性能:吞吐量越高代表性能越好、暂停时间越短也代表越好。那么如何做到这两点呢?核心思想在于:

  • 尽可能让对象在新生代中分配和回收。
  • 尽量避免过多对象进入年老代,缩短年老代GC时间。
  • 尽量给JVM分配足够多的内存,减少所有区域中的GC次数。

   归根结底,本质思想就一点:“尽量让Java中的对象去到它自己该去的位置”,短命的对象就老老实实的进入新生代区域,大对象和长命的对象则进入年老代空间,避免JVM因为对象“乱窜”导致GC频发和GC时间变长,如:

  • 本该在新生代的短命对象由于特殊原因进了年老代,导致年老代GC次数变多/时间变长。
  • 本该直接分配在年老代的长命大对象,因为某些原因全部被分配在新生代,导致新生代可分配空间变少,引发分配担保机制,造成大量未达到标准的新生代对象提前进入年老代。

因此,GC调优的目的就相当于给JVM做“保养”,让其每个区域按照设计的初衷正常工作。

   通常情况下,当JVM存在性能问题时,都会牵扯到两个概念,分配速率(Allocation Rate)和提升速率(Promotion Rate),这也是分析性能问题时常用的两个指标,其中分配速率影响新生代的垃圾回收,提升速率影响年老代的垃圾回收。

1.2、年老代-提升速率(Promotion Rate)

   前面分析的分配速率仅会对新生代空间造成影响,而影响年老代空间的则是另外一个指标:提升速率,也就是指定时间内,新生代升入年老代空间的对象总量,通常单位也为MB/S

在前面谈论分配速率时,可以根据GC日志计算新生代的分配占比,但新生代升入年老代空间的提升速率又该如何计算呢?因为MajorGC一般都是伴随着FullGC一起发生的,所以无法根据MajorGC计算,比较FullGC时会回收整堆空间。

1.2.1、提升速率如何计算?

   同样计算提升速率时,依旧是通过MinorGC日志来计算:

 
1.514: [GC (Allocation Failure) [PSYoungGen: 38395K->5120K(71680K)]45665K->35687K(159232K), 0.0570688 secs] [Times: user=0.09 sys=0.00, real=0.06 secs] 
3.018: [GC (Allocation Failure) [PSYoungGen: 70326K->5104K(71680K)]100894K->105240K(172032K), 0.0866792 secs] [Times: user=0.30 sys=0.02, real=0.09 secs] 

提升速率计算公式:((新生代回收前使用总量-新生代回收后使用总量)-(整堆回收前使用总量-整堆回收后使用总量))/(本轮GC时间-上轮GC时间)

GC轮数时间差值新生代减少整堆减少提升量提升速率
第一轮763ms33275KB9978KB23297KB≈30MB/S
第二轮1504ms65222KB3700KB61522KB≈40MB/S
每轮均速NULLNULLNULLNULL≈35MB/S

结果如上表,此刻是通过MinorGC日志来计算的提升速率,拆解前面的计算公式可以分析出整体的计算逻辑:

  • 先通过新生代回收前后的已使用容量大小,计算出新生代中减少容量。
  • 再通过整堆回收前后的已使用容量大小,计算出整个堆空间的减少容量。
  • 再通过新生代减少-整堆减少,这样可以大致算出新生代中提升到年老代的提升量。
    • 该方式只能计算出大概的提升量,因为整堆减少会包含年老代、元空间等区域回收。
  • 在通过本次GC触发时间-上次GC触发时间,得到本轮GC中程序正常执行的时长。
  • 最后通过提示量除执行时长,即可得到JVM的大概提升速率。

不过在计算提升速率的时候,有个点需要额外注意:Java应用启动后的第一条GC日志不能参与计算,因为第一条GC日志是程序启动后,初次触发GC时输出的,此时堆空间刚从“冷状态”启动,因此测算出的速率并非程序正常执行时的提升速率。

1.2.2、提升速率对JVM的影响

   和分配速率相同,提升速率也一样会影响GC,但它影响的是年老代空间,速率越快也就代表着提升的对象越多,年老代空间被填满的时间会更短,MajorGC被触发的频率也会越快。不过通常情况下,年老代的GC一般会伴随着FullGC一起发生,因此,提升速率越高会最终导致FullGC频率越快。

1.2.3、进入年老代的三种异常情况
  • ①代码存在内存泄漏

当代码中存在内存泄漏时,会造成堆内存被一点点蚕食,最终导致新生代空间没有空闲内存分配新对象,从而触发JVM的空间分代担保机制,开启对象动态晋升阈值判定,将大量原本未达晋升标准的对象提前迁入年老代空间,以确保新生代拥有足够的空闲内存维护Java应用的正常执行。
常发性内存泄漏、偶发性内存泄漏、一次性内存泄漏、隐式内存泄漏,不同性质的内存泄漏造成的提升速率增长也不同,后两者引发的速率增长并不大,但前两者,尤其是常发性内存泄漏会带来很大的隐患,最终必然会引发OOM。

  • ②频繁的大对象分配

在分代堆中有这么一条法则:“超过指定阈值的大对象会被直接送往年老代空间”,这条结论是依据对象特性而制定的,正常情况下,大对象都不会是“朝生夕死”的对象,一般都能够“活”到成功晋升。因此,为了节省大对象在两个Survivor区中反复挪动带来的开销,JVM会将超过阈值标准的大对象直接分配到年老代。
大对象直接进入年老代是合理的,但频繁的大对象分配是不合理的,会导致年老代被快速填满,因而频繁触发FullGC
大对象直接进入年老代空间,因此大对象分配是不参与前述的提升速率计算公式的。

  • ③高并发/大流量压力

当系统业务暴涨时,巨大的流量和并发冲击会导致业务线程创建更多的新对象,因而会导致新生代的GC阈值被频繁触发,加快了新生代整体的晋升速度,从而导致提升速率暴涨。
对于这类正常业务增长导致的提升速率变高,这是系统中的常事,这种情况下只需依照具体业务流量的增长,合理的调大堆空间即可。

   其实归根结底,上述三点都是在围绕着“对象被过早提升到年老代”这一核心思想展开。对于年老代而言,新生代空间中的所有对象,按部就班的活到15岁再晋升是最佳的状态,因为能够在新生代熬过十多轮GC的对象晋升后,绝大多数情况下会再存活很长一段时间。
但如果是由于上述三种状况导致对象过早提升到年老代空间,则会带来很大的不稳定因素,有可能很多提早晋升的对象刚晋升,没熬过几轮GC就“死”了,从而违背了“年老代存放长命对象”的设计初衷。同时,过早提升还会造成年老代会被快速填满,从而频繁触发FullGC,最终导致Java应用暂停时间过长,影响系统整体的吞吐量。

1.2.4、年老代空间调优思想

   年老代空间调优的核心就一点:避免或尽量减少过早提升,为何不是降低提升速率呢?因为在业务规模比较大的情况下,提升速率比较高也是合理的。所以在调优年老代时,只需要将过早提升的对象依旧控制在新生代即可。

过早提升的表现
  • ①一次FullGC后,年老代的空间占用比极速下降。
  • ②短时间内频繁触发FullGC
  • ③提升速率接近分配速率。
  • ④新生代GC发生后,新生代的空间占用比下降到20%以内。
过早提升如何解决?

   处理过早提升时,需要根据具体的情况来决定采取何种措施:

  • ①如果是业务或流量压力变大导致的,那么增大新生代空间即可。
  • ②如果是代码中存在问题,如内存泄漏或循环体中创建对象等,优化代码即可。
  • ③如果是短命的大对象分配,如大数组,则可以考虑优化数据结构,如换成链表。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/797904.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

模型CLIP-ViT-B-32-IMAGE.zip

模型CLIP-ViT-B-32-IMAGE.zip

TikTok防关联封号及操作需注意什么?

现在Tiktok对账户的管控一直非常严格。在运营Tiktok账户时,应该注意哪些方面来减少账户损失?以下是几个账户可能出现问题的原因。 网络环境问题 1.Tiktok账户对账户有严格的控制。我们经营Tiktok账户,手机应该模拟海外环境。一旦平台发现我…

全网短剧搜索前端源码开源分享可改自己的接口

全网短剧搜索前端源码 内含7000短剧资源(不支持在线播放) 源码全开源,可以修改成自己的接口 178、226、347行修改 源码免费下载地址抄笔记 (chaobiji.cn)https://chaobiji.cn/

【算法】求平方根 - 二分法/牛顿迭代

题目 求一个数的平方根,要求返回小于等于平方根的正整数。 原理 二分法 遍历每次取中间数,大了就往小取,小了就往大取,直到取到正确的值。 牛顿迭代 求num的平方根,则是求 num / x 和 x 的均值,这个值…

linux 文件提权|属性修改

文章目录 suid(set uid)添加文件属性查看文件属性i (immutable) umask suid(set uid) 让文件在执行的时候具有属主(对应文件 user )的权限 chmod 7744 temp.txt 第一位的7表示权限位…

数据库的基本使用

一、数据库的简介 RDBMS简介: Relational Database Management System,通过表来表示关系类型。当前主要使用两种类型的数据库:关系型数据库和非关系型数据库。所谓的关系型数据库RDBMS是建立在关系模型基础上的数据库,借助于集合代数等数学概念和方法来…

全量知识系统 程序详细设计之架构设计:一个信息系统架构

统架构,整体设计分成了三部分--三种方面:信息nformation、系统Syste 原文 以下是对全知系统程序详细设计需要的架构规划的考虑。 全知系统架构是一个信息系统架构,整体设计分成了三部分(三种“方面”):信…

蓝桥杯第十三届省赛C++B组(未完)

目录 刷题统计 修剪灌木 X进制减法 【前缀和双指针】统计子矩阵 【DP】积木画 【图DFS】扫雷 李白打酒加强版 DFS (通过64%,ACwing 3/11); DFS(AC) DP(AC) 砍竹子(X) 刷题统计 题目描述 小明决定从下周一开始努力刷题准…

洛谷 P3512 [POI2010] PIL-Pilots

首先就是对于超时的做法进行展示&#xff0c;这个思路是最原始的思路&#xff0c;也就是用单调队列的板子&#xff0c;用了两次&#xff0c;然后求差值&#xff0c;差值满足条件我们就直接返回这个长度&#xff0c;然后和后面的循环的长度进行相比。 #include<iostream>…

《QT实用小工具·十八》高亮发光按钮控件

1、概述 源码放在文章末尾 该项目实现了高亮发光按钮控件 可设置文本&#xff0c;居中显示。可设置文本颜色。可设置外边框渐变颜色。可设置里边框渐变颜色。可设置背景色。可直接调用内置的设置 绿色、红色、黄色、黑色、蓝色 等公有槽函数。可设置是否在容器中可移动&#…

git应用场景(进阶)

Git场景运用-CSDN博客 专有名词 Workspace&#xff1a;工作区 Index / Stage&#xff1a;暂存区 Repository&#xff1a;仓库区&#xff08;或本地仓库&#xff09; Remote&#xff1a;远程仓库HEAD HEAD&#xff0c;指向当前分支最新提交点。所处分支变化&#xff0c;或产生新…

Open CASCADE学习|旋转变换

物体在三维空间中的旋转变换操作通常可以通过三种不同的方式来表示&#xff1a;矩阵&#xff08;Matrix&#xff09;、欧拉角&#xff08;Euler Angles&#xff09;和四元数&#xff08;Quaternion&#xff09;。下面详细解释这三种表示方法。 矩阵&#xff08;Matrix&#xf…

centos后台运行使用nohup命令

nohup ./my_script.sh & nohup命令运行后如何关闭 nohup 命令用于在用户注销系统后继续运行指定的命令。如果您想关闭使用 nohup 运行的进程&#xff0c;您可以使用 kill 命令。 首先&#xff0c;您需要找到 nohup 运行的进程的进程ID&#xff08;PID&#xff09;。可以使…

【云开发笔记No.21】如何建设中台

这里主要讨论一下中台的建设步骤和组织方法。 随着企业业务的快速发展和数字化转型的深入&#xff0c;中台建设成为众多企业追求高效运营和创新发展的关键一环。中台&#xff0c;作为一个集成了业务、数据和技术的共享服务平台&#xff0c;旨在实现资源的统一管理和高效复用。…

C++的并发世界(八)——lock_guard和unique_lock

1.lock_guard lock_guard是C的stl库中的一种互斥量封装嘞&#xff0c;用于保护共享数据&#xff0c;防止多个线程同时访问同一资源而导致的数据竞争问题。&#xff0c;其包括以下成员函数&#xff1a; 函数名作用lock尝试对互斥量进行加锁&#xff0c;如果当前互斥量已经被其他…

写JDBC遇到的问题

执行会出现以下错误信息 java.sql.SQLSyntaxErrorException: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ? and loginPwd ? at line 1 at com.mysql.cj.jdbc.exceptions…

Unix Domain Sockets (UDS) 简介

Unix Domain Sockets (UDS) 是一种进程间通信&#xff08;IPC, Inter-Process Communication&#xff09;机制&#xff0c;特别适用于在同一台主机操作系统上运行的多个进程之间进行高效的数据交换。它是基于文件系统路径或者匿名内存区域创建的套接字&#xff08;socket&#…

图书管理系统

❤️❤️前言~&#x1f973;&#x1f389;&#x1f389;&#x1f389; hellohello~&#xff0c;大家好&#x1f495;&#x1f495;&#xff0c;这里是E绵绵呀✋✋ &#xff0c;如果觉得这篇文章还不错的话还请点赞❤️❤️收藏&#x1f49e; &#x1f49e; 关注&#x1f4a5;&a…

sqlalchemy中Datetime的创建时间-修改时间之default|server_default|onupdate

default vs. server_default 的区别 default 这个属性 &#xff0c;就是默认生成orm 对象,如果某个字段没有 传值&#xff0c;就使用default 值&#xff0c;然后写入到数据库中。 server_default 这个属性&#xff0c;要求是一个str, unicode 类型。 用来生成表结构的时候&am…

Vue - 你会在同一个元素上使用v-for和v-if吗

难度级别:初级及以上 提问概率:50% 在初学者看来,v-for和v-if同时使用是非常方便的,二者共同使用的常见场景有两种。例如有两个列表,分别用于渲染学生数据和老师数据,然后有两个单选按钮,用于切换当前页面中需要展示学生列表还是老师列…