不会JVM调优怎么进互联网大厂

news2024/12/27 13:49:43

📣📣📣📣📣📣📣

🎍大家好,我是慕枫
🎍前阿里巴巴高级工程师,InfoQ签约作者、阿里云专家博主,一直致力于用大白话讲解技术知识
🎍在这里和大家分享一线互联网大厂面试经验、技术人成长路线以及Java技术、分布式、高并发、架构设计方面的经验总结
🎍感恩遇见,希望我们都能成为更好的自己
📣📣📣📣📣📣📣
 

目录

预估比调优更重要

为什么需要进行预估

如何进行预估

JVM调优思路JVM

JVM常见配置参数

JVM常见垃圾回收器

总结


如果说有什么在面试中经常被问到,但是在实际工作中又不经常用到的Java技术,那么JVM调优绝对可以排得上号。每当有同学被问到这个问题的时候,内心的OS大概是这样:我一个QPS几百的系统,有啥好调优的,默认配置用用得了,调JVM参数整不好系统还能干崩了,想想好像是这么个道理。但是对于一些高并发大流量业务场景,JVM调优就有用武之地了。因此个人觉得JVM调优也许不像SQL调优或者代码优化在工作中使用得那么频繁,甚至很多时候其实是用不上的,但是在需要用到的时候如果你能顶得住压力完成优化,那么你和其他人的不同就显现出来了。另外如果我们想进入一线互联网大厂,那么JVM调优就是必须要掌握的重要技能。

那么JVM到底应该怎样调优呢?有没有什么套路我们可以学习?本文主要着眼于如何进行参数预估以及JVM优化,希望对大家平时工作可以有所裨益。

预估比调优更重要

为什么需要进行预估

所谓凡事预则立不预则废,对于JVM调优来说也是如此。无论修改线上已有JVM参数配置还是优化代码实际都是一种无奈之举,因为生产环境出现了运行异常不得不采用这种方式进行优化,从而保障线上应用服务能够正常运行,否则就要拉程序员出来祭天了。但是如果我们在服务发布部署之前可以预估服务的容量而后进行对应的JVM参数配置,那么就相当于把可能出现的JVM异常扼杀在摇篮中。当然这是最理想的状态,在现实中也实际不容易做到,但是即便我们不能预估的那么准确,也总比不做容量预估直接裸奔上线的好。因此关于JVM调优这件事情,实际和《孙子兵法》的核心思想有异曲同工之妙,上兵伐谋,其次伐交,其次伐兵,其下攻城。也就是说JVM调优最高境界是预估不调,打仗最高境界是不战而胜。

如何进行预估

JVM参数预估基本流程

在明确了JVM参数预估对于生产环境中服务稳定运行的意义之后,我们一起看下如何进行JVM参数预估。首先我们应该先分析下自己系统的核心业务流程是什么,然后根据核心业务流程结合线上可能的流量,确认好我们核心业务代码中的对象创建以及销毁情况是怎样的,最后再针对性的进行相关JVM参数的预估配置。因此JVM参数预估的地址基本流程如下所示:

案例驱动

这里以一个实际的业务场景案例来帮助大家更好理解JVM参数预估的过程。假设有这样一个电商平台,它主要由商品中心、订单中心、营销中心、库存中心等子系统组成。那对于电商系统来说最核心的业务就是用户下单购物,我们就以用户下单购物这个业务流程来看看如何进行估算JVM参数。

假设平台有1个亿的注册用户,日活用户1000万,这些用户会在电商平台进行浏览商品、下单购买以及收货评价等操作,但是实际上真正下单购买的用户并没有那么多,如果有10%的转化率,那么就相当于每天电商平台有100w个订单。另外一般情况下这些订单主要分布在一天当中的高峰时间,比如中午或者晚上,毕竟其他时间大家要忙碌工作以及其他事情,中午休息或者晚上休息的时候才会有时间逛平台买买买。如果我们把用户购买的高峰时间定为3小时,也就是说极端情况下将所有的订单的生成都分布在这三个小时中完成,也就是每小时产生33万个订单,每秒产生92个订单左右。

在估算订单对象大小之前,我们先来看下堆中的对象由哪些元素组成。一个JVM对象的大小主要由三部分组成,分别是对象头、数据以及数据补齐。对象头以及对象补齐基本变化不大,因此对象的大小实际和对象中的属性有直接关系,对象中的属性越多,对象占用的空间大小也就越大。

Mark Word:主要存储对象自身的运行数据,包括HashCode、GC分代年龄锁状态标志、线程持有的锁等信息,根据操作系统位数的不同而不同,32位的操作系统对应的大小就是32bit,64位的操作系统对应的大小就是64bit;

Klass Pointer:指向对象对应的Class对象的内存地址,根据不同的操作数系统占用空间不同,在64位系统中占用8个字节;

Array Length:如果当前对象是一个数组对象那么此处存储的就是数组的大小,占用4个字节,如果不是数组对象那么就不占用。

回到我们刚才的案例当中,我们来具体估算一个订单对象大概占多少内存空间。订单对象主要包括了如下的属性:订单编号、商品编号、商品价格、创建时间、付款时间以及发货时间等,当然实际订单可能不止这些属性,我们只是说明对象大小估算的方法,因此对属性进行了相应的裁剪。如果数据层面包含了这些属性,那么数据部分的占用空间大小就是这些属性的大小总和。总共估算下来应该不到1kb,但是实际考虑到其他各种占用以及平台中肯定不止订单这一种对象,还会有库存对象、积分对象、物流对象、营销对象等等,因此我们考虑将对象的总和扩大30倍进行估算,也就是说平台中产生的各种对象的总和为30乘以1kb即为30kb。如果每秒产生92个对象的话,那么就相当于每秒产生2760kb的对象,也就是大概2Mb的对象,另外由于电商平台中布置下单这一个操作,还会包含订单查询、商品查询等等其他业务那么综合起来我们再放大10倍,也就是说每秒JVM中新增20Mb左右的对象。对于一台4核8G的服务器来说,我们可以为服务分配3G左右的堆内存,512Mb左右的元空间。

但是考虑到电商平台存在大促场景,这个时候的流量可能是平时的好几倍,因此我们实际上需要将堆内存中的年轻代进行放大,Eden区可以到1.6G,Survivor区可以各自200M。这样可以避免由于年轻代空间不足导致对象提前进入老年代而造成fullGC的频率变高,从而影响服务的稳定性。

JVM调优思路JVM

理想情况下预估的JVM参数应该可以cover线上的业务场景,但是假如公司业务发展飞快,业务体量迅速膨胀,原先预估的JVM配置参数可就不一定能满足线上生产环境所有情况,因此异常情况还是会出现。这里将JVM异常主要分为两类,一种是代码导致的JVM异常,另一种是JVM不合理配置导致的异常,包括JVM参数以及服务器内存配置。

代码导致的JVM异常

代码Bug应该是导致JVM异常最常见的情况,这种情况我们只能通过调整代码才能实现优化,因为即使临时调整JVM参数也只是缓兵之计,并没有根除问题所在,随着时间的推移,业务的发展问题还是会暴露。所以要想解决根本问题还是需要定位问题代码来进行优化。

那么首先我们就需要能够有手段定位到到底哪部分代码导致JVM异常。一般分为两种情况,一种就是已经发生内存溢出了,另一种是还没有发生内存溢出但是已经在崩溃的边缘,系统响应也变慢了。如果我们配置了-XX:HeapDumpPath参数,当JVM发生内存溢出的时候就可以到对应的目录去找到hprof文件。如果还没有发生内存溢出,这个时候我们可以通过操作命令jmap -dump:format=b,file=/tmp/文件名.hprof <PID>来手动导出内存快照来进行进行分析。有了hprof文件之后,我们可以通过MAT工具来分析和定位内存溢出代码位置,然后再进行针对性的优化。

Java代码引起的JVM异常可以分为以下几种情况,我们一起来看看有哪些:

(1)如下图的例子,客户端和服务端建立了websocket连接,如果连接未正常建立,又重新建立连接如果此时服务端未将连接关闭,那么就会导致重新使用新的请求对象,随着时间的累计JVM中出现大量对象来不及回收,导致JVM无法分配新的内存空间给服务中新产生的对象,最终导致JVM内存溢出。由于JVM中堆积了几千个RequestIInfo对象,同时服务还在不断产生新的RequestInfo对象,最终不可避免地就会发生OutOfMemoryError异常。通过MAT我们可以轻松定位到发生内存溢出的代码位置,搞清楚为什么会有RequestInfo对象被创建之后,我们就可以进行针对性的优化了。

(2)我们在实际项目开发的过程中必定会涉及到业务数据的查询,假如没有控制好数据查询的条件或者说本身查询的数据量就很大。那么就容易造成一次性查询大量数据,这些数据如果全部load到内存中就很容易导致内存溢出。所以一般涉及到数据查询的代码要做好相应的处理,分页查询也好,限制查询数据量也好或者流式查询也好,总之不能一次性将大量数据加载到内存中。

(3)在for循环或者while循环中大量创建对象,最终导致对象在对堆内存中堆积,这种是由于条件没有控制好条件导致对象被不断创建。

(4)我们都知道JVM运行时数据区的虚拟机栈是线程所独有的,JVM启动后会为每个线程的虚拟机栈分配固定大小的内存(-Xss参数),因此虚拟机栈的深度是确定的,如果代码中出现不合理的递归代码,就会造成虚拟机栈只入栈不出栈,最终导致虚拟机栈内存空间被耗尽,从而产生StackOverFlowError。

当我们知道了这些常见的可能导致JVM异常的代码结构之后,那么在平常做项目编写代码的时候就要时刻保持警惕。写完代码之后自己再回头看看这段代码的对象创建情况是怎样的,有没有大对象缓存,有没有不合理的while循环for循环,会不会有可能造成JVM内存溢出。当我们有了这样反观代码的意识之后,从根本上JVM内存溢出的概率大大降低,有益于线上服务的稳定性。

JVM参数不合理导致的异常

线上环境JVM参数不合理直接影响JVM运行稳定性。我们都知道对象都是存放在堆内存中的,而堆内存又被划分为年轻代和老年代,新产生的对象都会被分配在年轻代对应的堆内存中,如果此时我们设置的年轻代过小。那么对象进入到老年代堆空间的概率就会增大,当然引起full GC的可能性也会大大增加。因此JVM参数如果设置的不合理一般是堆内存大小、元数据区大小以及垃圾回收器。另外我们需要根据不同的业务场景来选择对应的垃圾回收器,如果对于停顿时间有比较高的要求可以考虑G1和ZGC。

通过上文我们可以明确无论是优化业务代码还是参数调优,其实都是在避免在堆中遗留过多的对象。可以看得出来,JVM调优的本质思想其实就是生产者-消费者模型,为什么这么说呢?你看一方面随着平台业务的不断进行,JVM中会不断产生对象,那么平台就相当于对象生产者。另一方面垃圾回收器这个勤劳的小蜜蜂在不断检测哪些对象已经是垃圾对象,然后根据策略进行垃圾回收释放内存空间,那么JVM就相当于对象消费者。一个生产对象,一个消费对象,这可不就是生产者消费者模型嘛。所以从这个角度来看,生产者和消费者的动态平衡才能保证JVM的正常运行,如果对象生产地快,而对象回收地慢就会导致内存溢出等JVM异常。所以JVM调优从本质上来说,就是通过各种手段构建对象生产与回收的动态平衡。

JVM常见配置参数

无论是发布部署前的JVM参数预估还是异常过后的参数优化,都是需要通过调节JVM对应的参数来完成的,因此我们需要掌握常用JVM参数项及其含义。

配置项含义

-Xms

初始堆大小
-Xmx初始堆最大值
-Xmn堆中新生代最大值
-XX:SurvivorRatiosurvivor区与Eden区的比例
-XX:NewRatio新生代和老年代的比例
-XX:MetaspaceSize初始元空间大小
-XX:MaxMetaspaceSize元空间最大大小
-Xss线程虚拟机栈大小
-XX:+HeapDumpOnOutOfMemoryError开启内存溢出时进行内存快照
-XX:HeapDumpPath=/data/dump/jvm.hprof内存快照文件路径

JVM常见垃圾回收器

随着JDK版本的不断迭代,垃圾回收器同样也在不断迭代优化。当然不同的业务场景,我们可以选择不同的垃圾回收器来进行应对,而垃圾回收器也在向着回收效率高、停顿时间短的目标不断进行调整改进。

垃圾回收器引入版本特点适用场景

Serial GC

JDK3

单线程方式进行垃圾回收,暂停所有应用线程

适用于小型应用,单CPU的系统或者不需要高并发的场景

ParNew GCJDK3Serial GC多线程实现年轻代垃圾回收

Parallel GC

JDK4

利用多CPU、多核心的系统资源,提高垃圾回收效率

对吞吐量有要求的应用场景,如数据处理、科学计算等

CMS GC

JDK5

采用多线程方式进行垃圾回收,能够缩短应用程序的暂停时间

适用于对响应时间有要求的应用场景

G1 GC

JDK7

内存划分为一个个Region,可以指定停顿时间

适用于部署早多核CPU大内存机器上的大型应用,对停顿时间有一定要求,

ZGCJDK11支持超大堆空间,最大停顿时间不超过10ms业务对于停顿时间低于100ms

总结

任何技术上的优化都是建立在对技术原理的深刻理解基础之上的,JVM调优亦是如此。文章中常见的JVM调优手段只不过是一些术,搞懂JVM的运行原理以及垃圾回收机制才是关键。另外在调优前我们得先搞清楚我们调优的目标是什么,有了目标的指引,我们才能做到有的放矢。其实无论是性能优化还是业务优化其实都是有一定的规律可以摸索,万变不离其宗,都是通过观:观察当前是个什么样的状态;析:分析整条业务链路找到可以优化的方向以及改造点;优:动手制定优化策略以及验证方法进行优化实操。

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

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

相关文章

设计模式七大设计原则

文章目录 1、什么是设计模式2、单一职责原则3、开闭原则4、接口隔离原则5、依赖倒置原则6、迪米特法则&#xff08;最少知道原则&#xff09;7、里式替换原则8、组合优于继承 设计模式主要是为了满足一个字 变&#xff0c;这个字&#xff0c;可能是需求变更、可能是场景变更&a…

【VAR | 时间序列】以美国 GDP 和通货膨胀数据为例的VAR模型简单实战(含Python源代码)

以美国 GDP 和通货膨胀数据为例&#xff1a; 1. 数据集 下载数据我们需要从 FRED 数据库下载美国 GDP 和通货膨胀数据&#xff0c;并将它们存储在 CSV 文件中。可以在 FRED 网站&#xff08;https://fred.stlouisfed.org/&#xff09;搜索并下载需要的数据。在这里&#xff0…

非静压模型SWASH学习(7)——自制算例Lock-Exchange

自制算例Lock-Exchange 算例简介模型配置网格及参数设置网格与地形初始条件与边界条件物理参数设置数值求解方法模型输出计算时间 模拟结果 SWASH是由Delft大学开发&#xff0c;用于模拟非静压条件下的水动力/波浪运动的数值模型。 与模型原理相关的内容详见以下论文&#xff1…

Centos系统安装RabbitMQ消息中间件

记录一下在centos7.x下面安装RabbitMQ消息中间件 RabbitMQ是一个开源而且遵循 AMQP协议实现的基于 Erlang语言编写&#xff0c;因此安装RabbitMQ之前是需要部署安装Erlang环境的 先安装Erlang https://packagecloud.io/rabbitmq/ 点进去可以看到 因为使用的centos是7.x版本的…

内网渗透(六十二)之 NTLM Realy 攻击

NTLM Realy 攻击 NTLM Realy 攻击其实应该称为Net-NTLM Realy 攻击,它发生在NTLM认证的第三步,在Response 消息中存在Net-NTLM Hash,当攻击者获得了 Net-NTLM Hash 后,可以重放Net-NTLM Hash 进行中间人攻击。 NTLM Realy 流程如图所示,攻击者作为中间人在客户端和服务器…

asp.net基于web的音乐管理网站dzkf17A9程序

本系统主要包含了等系统用户管理、公告信息管理、音乐资讯管理、音乐类型管理多个功能模块。下面分别简单阐述一下这几个功能模块需求。 管理员的登录模块&#xff1a;管理员登录系统对本系统其他管理模块进行管理。 用户的登录模块&#xff1a;用户登录本系统&#xff0c;对个…

如何免费使用ChatGPT进行学术润色?你需要这些指令...

目录 1 ChatGPT4.0上线2 中科院ChatGPT学术版3 学术润色Prompts 1 ChatGPT4.0上线 2023年3月14日&#xff0c;OpenAI发布ChatGPT4.0。ChatGPT4.0比3.5更大&#xff0c;拥有更多的参数。这意味着它可以更好地捕捉和理解语言的复杂性和细微差别&#xff0c;而且ChatGPT4.0是多模…

【五一创作】《嵌入式系统》知识总结6:GPIO的结构和功能

GPIO的结构和功能 1.STM32提供通用的输入输出引脚&#xff08;GPIO&#xff09; • 输出高低电平控制外设 • 输入0、1检测外设状态 2.可配置为复用的输入输出引脚&#xff08;AFIO&#xff09; • 大多数GPIO都有默认的复用功能&#xff1a; 可作为片上外设&#xff08;如…

基于MobileNet的人脸表情识别系统(MATLAB GUI版+原理详解)

摘要&#xff1a;本篇博客介绍了基于MobileNet的人脸表情识别系统&#xff0c;支持图片识别、视频识别、摄像头识别等多种形式&#xff0c;通过GUI界面实现表情识别可视化展示。首先介绍了表情识别任务的背景与意义&#xff0c;总结近年来利用深度学习进行表情识别的相关技术和…

android基础知识

架构&#xff1a; 应用框架层&#xff08;Java API Framework&#xff09;所提供的主要组件&#xff1a; 名称功能描述Activity Manager&#xff08;活动管理器&#xff09;管理各个应用程序生命周期&#xff0c;以及常用的导航回退功能Location Manager&#xff08;位置管理器…

智能是逻辑吗?

智能是指人或机器能够理解、学习、推理、解决问题和适应环境的能力。而逻辑是一种推理方式&#xff0c;它是智能中的一部分&#xff0c;帮助我们正确地推理和理解信息。逻辑能够提高我们的思考能力、解决问题的能力和决策能力&#xff0c;但智能还包括其他方面&#xff0c;如感…

数据结构课程——第一次作业

T1:Gram_ham实现凸包算法&#xff1a; &#xff08;1&#xff09;思路&#xff1a; &#xff08;2&#xff09;代码&#xff1a; #include<iostream> #include<string> #include<vector> #include<algorithm> #include<stack>using namespace …

存储网络架构——DAS、NAS、SAN、分布式组网架构

目录 DAS直连式存储 NAS网络附加存储 SAN存储 存储区域网络 分布式存储组网 DAS直连式存储 DAS遇到的挑战 NAS网络附加存储 向主机提供文件服务&#xff1b;文件系统由存储设备维护&#xff0c;用户访问文件系统&#xff0c;不直接访问底层存储 拥有所有主机上文件与底层存储空…

图像复原与重建

文章目录 一、实验目的二、实验内容1. 噪声图像及其直方图。2. 空间噪声滤波器。3. 逆滤波。 一、实验目的 了解一些常用随机噪声的生成方法。掌握根据指定退化函数对图像进行退化的方法。掌握当模糊图像只存在噪声时的几种滤波复原方法。掌握当模糊图像同时存在线性退化和噪声…

OpenCV C++案例实战三十一《动态时钟》

OpenCV C案例实战三十一《动态时钟》 前言一、绘制表盘二、绘制刻线三、获取系统时间四、结果展示五、源码总结 前言 本案例将使用OpenCV C实现动态时钟效果。原理也很简单&#xff0c;主要分为绘制表盘、以及获取系统时间两步。 一、绘制表盘 首先为了效果显示美观一点&…

数据驱动测试、结果报告生成,Python接口自动化测试全方位解析

B站首推&#xff01;2023最详细自动化测试合集&#xff0c;小白皆可掌握&#xff0c;让测试变得简单、快捷、可靠https://www.bilibili.com/video/BV1ua4y1V7Db 目录 一、背景 二、准备工作 三、编写测试脚本 四、数据驱动测试 五、结果报告生成 六、总结 七、参考链接 …

线性表,顺序表,链表

线性表 线性表&#xff08;linear list&#xff09;是n个具有相同特性的数据元素的有限序列 线性表是一种在实际中广泛使 用的数据结构&#xff0c;常见的线性表&#xff1a;顺序表、链表、栈、队列、字符串... 线性表在逻辑上是线性结构&#xff0c;也就说是连续的一条直线 …

阿里云对象存储OSS使用 HTTPS访问

阿里云对象存储OSS使用 HTTPS ​ 在部署项目的时候遇到了一个问题&#xff0c;就是https页面访问http资源报错的问题。 问题&#xff1a; 写了一个前端项目在云服务器部署&#xff0c;我的域名申请了ssl证书并在云服务器nginx部署&#xff0c;所以页面是https页面&#xff0c;但…

Ansible的脚本-playbook 剧本

目录 1.剧本&#xff08;playbook&#xff09; 1.playbook介绍 2. playbooks 的组成 3.案例&#xff1a;编写httpd的playbook 4.定义、引用变量 5.指定远程主机sudo切换用户 6.when条件判断 7.迭代 2.playbook的模块 1.Templates 模块 2.tags 模块 3.Roles 模块 1.…

TCP协议——这篇文章GET全

TCP协议文章目录 1. UDP和TCP协议的比较1.1 UDP协议1.2 TCP协议1.3 特点比较 2. TCP协议建立连接的三次握手3. TCP协议断开连接的四次挥手4. TCP协议的几个特性4.1 确认应答4.2 超时重传4.3 连接管理4.4 滑动窗口4.5 流量控制4.6 拥塞控制 1. UDP和TCP协议的比较 UDP和TCP作为…