jvm之分析调优

news2024/11/24 17:17:57

写在前面

jvm调优不管是工作中还是面试中都异常重要,是衡量一个开发人员技术水平的重要指标,这也是个人的一个弱项,希望通过本文能够提高自我,也更能帮助到正在阅读文章的你,我们就开始吧!

1:重要的指标

如果是医生给病人看病,是需要根据各种指标的高低来对病人做出诊断的,分析jvm也是一样,这里我们主要看下两个指标,分别是分配速率和提升速率,解释如下:

分配速率:单位时间内eden生成的对象大小,单位m,即m/s
提升速率:单位时间内从young提升到old的对象大小,单位m,即m/s

1.1:分配速率

分配速率,我们并没有办法直接获取,但是可以通过GC日志来间接获取,方法是计算出某次GC距离上次GC新增的对象的数量,并除以两次GC间隔的时间就行了,如下的GC日志:

在这里插入图片描述

第一次GC:
    生成的对象量是33280K,经历的时间是0.291s,分配速率为33.280m/0.291s=33280m/291s=114m/s
第二次GC:
    生成的对象量是38368k-5088k=33280k,经历的时间是0.446-0.291=0.155,分配速率为33.280m/0.155s=33280m/155s=214.7m/s
第三次GC:
    生成的对象量是71680k-5120k=66560k,经历的时间是0.829-0.446=0.383,分配速率为66.560m/0.383s=66560m/383s=173.7m/s
三次GC总共产生的对象量是33280K+33280K+66560k=133120k,总时间是0.829s,平均分配速率是133.120m/0.829s=133120m/829s=160.5m/s

当分配速率过高,就会导致young GC次数增多,进而造成stw时长增加,进而会降低系统的吞吐量。

1.2:提升速率

先看一个概念,提升过早,提升过早是指对象过早的从年轻代被提升到老年代,如果提升过早严重则就会导致频繁的major GC,major GC并不是为了频发回收而设计的,其更多的是一种兜底的方案,而衡量是否过早提升的的治疗就是提升速度,计算提升速度类似于分配速度,都可以通过gc日志的对象量以及时长信息反推出来,如下图:

在这里插入图片描述

第一次GC:
    年轻代减少了33280k-5088k=28192k,整个堆内存减少了33280k-24360k=8920k,因此晋升到老年代的对象大小是28192k-8920k=19272k,平均提升速率19272m/291m=66m/s
第二次GC:
    年轻代减少了38368k-5120k=33248k,整个堆内存减少了57640k-46240k=11400k,因此晋升到老年代的对象大小是33248k-11400k=21848k,平均提升速率是21848m/(446-291)s=21848m/155s=140.9m/s
第三次GC:
    年轻代减少了71680k-5120k=66560k,整个堆内存减少了112800k-81912k=30888k,因此晋升到老年代的对象大小是66560k-30888k=35672k,平均提升速率是35672m/(829s-446s)=35672m/383s=93.1m/s
三次GC晋升的对象总量是19272k+21848k+35672k=76792k,总的提升速率是76792m/829s=92.63m/s

1.3:调优实战

1.3.1:young GC时间长

现象是GC stw时长特别长,400多毫秒,长的达到了540多毫秒,怀疑是发生了full GC,但通过查看GC日志,并没有,因此确定是因为发生了young GC,因为当时使用的是jdk8,配置参数如下:

-Xmx4g -Xms4g

而jdk8默认的GC策略 是并行GC,并行GC是一种吞吐量优先的GC算法,所以我们就怀疑是垃圾收集器为了维持吞吐量而牺牲掉了stw时长,而G1在jdk8已经成熟,所以就考虑使用G1垃圾收集器,修改为G1后配置参数为:

-Xmx4g -Xms4g -XX:+UseG1GC -XX:MaxGCPauseMillis=50

接着重启服务,运行观察,表现优秀,GC时长基本上维持在50ms以下,但程序运行了一天多之后,突然出现了一次超长时间的GC stw,时间达到了1.2s,相当残暴,有些不知所措,没有什么好办法,就是上网各种查G1的坑,也都没解决,那就看日志吧,修改参数如下打印GC日志:

-Xmx4g -Xms4g -XX:+UseG1GC -XX:MaxGCPauseMillis=50 -XX:+PrintGCDetails  -XX:+PrintGCStamps -Xloggc:/var/log/gc.log

,终于在日志中找到了如下的可疑信息:

[Parallel Time: 1861.0 ms, GC Workers: 48]

提示GC线程48个,这就奇怪了,因为我们的机器是4核的,GC线程怎么可能会这么高,虽然不知道为什么这么高,但严重怀疑这就是导致GC STW时长超长的真凶了,这么多的线程争抢4核势必造成非常严重的资源争抢,导致频繁上线文切换,所以先增加如下参数,限制GC线程数:

-XX:ParallelGCThreads=4

再重启,观察,问题解决,但为什么GC线程数会是48,之后经过和运维工程师的沟通,发现,是因为应用部署在k8s的环境中,k8s限制了pod只能使用4g的内存,只能使用4核cpu,但是物理机是72核的,而G1启动的工作线程数量的策略是这样的:

1:当核数小于等于8时,取核数
2:当核数大于8是,取(核数*(5/8)+3)

所以我们这里就是(72*(5/8)+3)=48,所以根本原因是JVM看到了物理机的72核,所以本质上,造成问题的原因是k8s的资源隔离不彻底,只是限制了pod使用4核,但是却让pod中的jvm看到了72核(其实是不应该看到的))。

1.3.2:young GC过于频繁

现象是这样子的,young GC很频繁,每秒1次,有时候每秒2次,每次GC 60ms 左右,不算长,通过jstat -gcutil ${pid} 1000 1000每秒打印1次,打印1000次,如下图:

在这里插入图片描述
为了进一步的印证young GC 过于频繁,我们将GC日志上传到gceasy.io , 发现其吞吐量只有93%。线上当前的配置如下:

-Xmx8g -Xms8g -Xmn2g -XX:+UseConcMarkSweepGC

很明显,young GC发生频繁,而且几乎没有full GC,所以是不存在内存泄漏问题,问题的原因是young区的内存大小太小了,所以就需要调大-Xmn,即增加年轻代的大小,以将young GC每4秒钟到5秒钟发生一次,作为优化目标来调整该参数,最终调整参数为-Xmn2.9g,但又发现gc 时长增加到了80ms左右,虽然时间也可以接受,但还是继续尝试优化这个时间,jvm使用的GC是CMS,而cms在年轻代使用的垃圾收集器是ParNew,ParNew采用的垃圾收集算法是复制算法,所以我们就希望能够减少在s0,s1之间复制对象的量来降低young gc的时间,想要实现这个效果,就需要调整参数-XX:MaxTenturingThreshold={age},这里age的默认值15,即15次young gc之后才会被提升到老年代,降低这个参数值,可以让对象提早提升到老年代就可以实现我们的目标了,但如何确定合适的年龄也是个问题,太小了,可能会导致会导致full GC,为了确定这个年轻,增加了参数-XX:PrintTenuringDistribution,配置如下:

-Xmx8g -Xms8g -Xmn2.9g -XX:+UseConcMarkSweepGC -XX:+PrintGCDetails -XX:+PrintGCDateStamps -Xloggc:d:\\test\\gc1423.log -XX:+PrintTenuringDistribution -Dfile.encoding=UTF-8

打印出不同分代对象的个数和大小信息,如下图(来自gceasy.io 分析结果):

在这里插入图片描述

可以看到存活区15岁的对象个数是8501,8岁的对象个数是8565,比例为8501/8565=99.2%,可以看到只要存活区到8岁的对象,存活到15岁的比例达到了99.2%,也就是达到8岁的对象就可以直接让其晋升到老年代了,因此调整参数-XX:MaxTenturingThreshold=7,这样就节省了8次大量存活对象从一个survivor区复制到另一个survivor区的成本,优化后,gc时间维持在了71ms左右,吞吐量也提高到了97%左右。

写在后面

参考文章列表

SuperBenchmarker(简称“sb“)压力测试工具详解 。

JVM工具之Arthas使用 .

一次线上JVM Young GC调优,搞懂了这么多东西! 。

线上问题排查思路

在这里插入图片描述

在这里插入图片描述

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

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

相关文章

Nginx 安装及部署项目

1. 下载nginx安装包 首先从官网下载 nginx,大家可以自己在百度搜索 nginx,进入官 网,或者在浏览中直接输入 nginx 的官方网址: http://nginx.org/ ,在此我直接提供 nginx 的下载链接,大家点进去之后可以按照 自己的需求下载自己所…

Flutter 笔记 | Flutter 核心原理(三)布局(Layout )过程

布局过程 Layout(布局)过程主要是确定每一个组件的布局信息(大小和位置),Flutter 的布局过程如下: 父节点向子节点传递约束(constraints)信息,限制子节点的最大和最小宽…

Vue项目iconfont新增svg图标

最近接手一个开发一半的Vue3的后台管理项目,由于样式需要,需要新增一些svg图标,项目使用的是iconfont接下来我会通过几个步骤在原来iconfont基础上去新增一些自己的图标; 一、iconfont文件转换为svg源文件; 通过访问ic…

电子商务客户消费购物预测模型-基于数千万真实在线零售数据__企业调研_论文科研_毕业设计(智慧营销_精准营销_机器学习_人工智能)

之前发过 《谁主沉浮?银行,消金,互联网公司的精准营销_智慧营销完全解读》介绍了智慧营销/精准营销目的是降低运营成本。但精准营销可以带来很多额外收益,例如提高销售利润,提高客户忠诚度,降低客户流失率&…

Ribbon入门使用 RestTemplate loadbance 负载均衡

一、概念 1. Ribbon Ribbon是实现一套客户端,负载均衡的工具,简单的说,ribbon是一个开源项目,主要提供给客户端软件负载均衡算法和服务调用。 负载均衡和服务调用的提供者 主要用于: 负载均衡 将用户的请求平均到分配多个微服务…

华为OD机试之二元组个数(Java源码)

二元组个数 题目描述 给定两个数组a,b,若a[i] b[j] 则称 [i, j] 为一个**二元组**,求在给定的两个数组中,二元组的个数。 输入描述 第一行输入 m 第二行输入m个数,表示第一个数组 第三行输入 n 第四行输入n个数&…

linux 安装、卸载docker(一)

安装流程 # 1.设置镜像仓库 yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo# 2.安装、更新yum软件包索引 // 安装yum,docker需要的安装包 yum install -y yum-utils // 更新yum软件包索引 yum makecache fast# …

pmp新手报名需要的步骤

球很多大中型企业,如华为、腾讯、字节、联想等,招聘项目管理相关人员时,都会把持有PMP证书当作必选或优选的招聘条件。 那么PMP的报考条件是什么呢?以下是PMI官网发布的PMP考试报考条件: 一、报名考生必须具备35小时…

不到一分钟,即刻拥有这 22 款插件主题

开源 API 管理工具 Postcat 的插件广场最近上新了插件主题,看了看,真的有几款我很喜欢。可能会有朋友有跟我一样的疑问,如何拥有这些好玩的插件主题。 第一步当然是找到 Postcat ,安装 Postcat ! 找到插件广场 浏览并选择喜欢的主…

云原生之部署Docker轻量级管理面板EasyDockerWeb

云原生之部署Docker轻量级管理面板EasyDockerWeb 一、EasyDockerWeb介绍1. EasyDockerWeb简介2. 环境要求3. EasyDockerWeb特点 二、本地环境介绍1. 本地环境规划2. 本次实践介绍 三、本地环境检查1.检查Docker服务状态2. 检查Docker版本 四、下载EasyDockerWeb镜像五、部署Eas…

25岁转行做软件测试1年多了,写给还在迷茫的测试圈朋友

相比开发以后的职业生涯;我更看好软件测试的未来。 其次具有开发经验。对软件测试会有相当大的帮助,前面学了测试基础工具后,后期自动化提升会更快。这样才能更好的胜任软件测试工作。 最重要的是测试不是青春饭,和软件开发相比…

VUE 3.0 -- 直播推拉流、流视频播放

🛴🛴前言: 该 Demo 基于 OBS推流 Nginx Vue 3.0 Nplayer.js hls.js ,目的只是实现流媒体播放,以及简易推拉流直播。 文章目录 前端组件 NPlayer.js安装 nplayer.js 流视频播放页面元素初始化播放器清晰度控件样式…

Linux中与命名空间相关的内核数据结构

【摘要】本文详细讲述了在Linux内核中与命名空间概念相关的内核数据结构及其内在联系。 十、命名空间(namespace)相关数据结构 Linux内核通过数据结构之间互相的连接关系,形成了一套虚拟的命名空间的虚拟化概念。 10.1 struct pid_namespace \linux-2.6.32.63\i…

关于数据科学的文本分析案例

在本文中,我们尝试通过进行一些文本挖掘来发现数据科学相关概念。我们将从一篇关于数据科学的文本开始,从中提取关键字,然后尝试可视化结果。 作为文本,将使用维基百科的数据科学页面: url https://en.wikipedia.org…

Java 高级应用-多线程-(二)线程安全问题及解决

当我们使用多个线程访问同一资源(可以是同一个变量、同一个文件、同一条 记录等)的时候,若多个线程只有读操作,那么不会发生线程安全问题。但是如 果多个线程中对资源有读和写的操作,就容易出现线程安全问题。 5.1 同…

四段论提问让ChatGPT更懂你心!

用户故事是描述客户需求的方法,通常记为四段论的格式: 角色-功能-目的-验收标准。 如: 作为一个家庭主妇,我需要一个30平方米的餐厅,用以招待10位客人聚餐。 我希望这个餐厅&…

Spring/SpringBoot与RabbitMQ整合

具体代码 依赖&#xff1a; <dependencies><!-- https://mvnrepository.com/artifact/com.rabbitmq/amqp-client --><dependency><groupId>com.rabbitmq</groupId><artifactId>amqp-client</artifactId><version>5.7.0</v…

定薪17K*15,阿里测开岗上岸面经分享....

先简单介绍一下我自己吧&#xff0c;等会大家以为我是什么学历狂人&#xff0c;技术大牛&#xff0c;我毕业于广东一个普通本科院校&#xff0c;绝对不是什么双一流大学&#xff0c;大家不要有距离感&#xff0c;这也是我为什么来分享的原因&#xff0c;因为我觉得我这段经验还…

github SSH 生成和使用(详细)

通过ssh连接github&#xff0c;可以有效的提升安全性 1.设置位置 2.生成ssh密钥&#xff08;windows&#xff09; 打开git bash&#xff0c;输入以下命名&#xff0c;把your_emailexample.com换成自己的github账号 ssh-keygen -t rsa -b 4096 -C "your_emailexample.co…

【计算几何】判断多边形边界顺逆时针 C++代码实现

文章目录 一、多边形边界顺序二、数学原理2.1 Green公式2.2 鞋带公式 三、代码实现 一、多边形边界顺序 多边形可以由一个点集 { v 1 , v 2 , . . . , v n } \{v_1,v_2,...,v_n\} {v1​,v2​,...,vn​} 表示&#xff0c;构成多边形的点集确定&#xff0c;多边形边界的顺序也就…