快速定位并优化CPU 与 JVM 内存性能瓶颈

1. CPU 性能优化实战

CPU(Central Processing Unit)是计算机系统的运算和控制核心,是信息处理、程序运行的最终执行单元,相当于系统的“大脑”。当 CPU 过于繁忙,就像“人脑”并发处理过多的事情,会降低做事的效率,严重时甚至会导致崩溃“宕机”。因此,合理控制 CPU 的负载,是保障系统稳定持续运行的重要手段。

CPU 使用率是 CPU 非空闲态运行的时间占比,它反映了 CPU 的繁忙程度。比如,单核 CPU 1s 内非空闲态运行时间为 0.8s,那么它的 CPU 使用率就是 80%;双核 CPU 1s 内非空闲态运行时间分别为 0.4s 和 0.6s,那么,总体 CPU 使用率就是 (0.4s + 0.6s) / (1s * 2) = 50%,其中 2 表示 CPU 核数,多核 CPU 同理。根据经验法则, 建议生产系统的 CPU 总使用率不要超过 70%。

CPU 使用率只反映系统健康状态的度量指标,并不是问题的根因。因此,它的价值主要体现在两个方面: 一是综合反映当前系统的健康程度,结合监控告警产品,实现快速响应;二是初步定界问题方向,缩小排查范围,降低故障恢复时间。 比如当 CPU iowait 高时,应优先排查磁盘 I/O;当 CPU steal 高时,就优先排查宿主机状态。CPU 涵盖的问题场景有很多,限于篇幅限制,下面以最常见的用户态 CPU 使用率高为例,介绍下 Java 应用的排查思路。

1.1 如何排查用户态 CPU 使用率高

用户态 CPU 使用率反映了应用程序的繁忙程度,通常与我们自己写的代码息息相关。因此,当你在做应用发布、配置变更或性能优化时,如果想定位消耗 CPU 最多的 Java 代码,可以遵循如下思路:
  • 通过 top 命令找到 CPU 消耗最多的进程号;
  • 通过 top -Hp 进程号 命令找到 CPU 消耗最多的线程号(列名仍然为 PID);
  • 通过 printf "%x\n" 线程号 命令输出该线程号对应的 16 进制数字;
  • 通过 jstack 进程号 | grep 16进制线程号 -A 10 命令找到 CPU 消耗最多的线程方法堆栈。

上述方法是目前业界常用的诊断流程,然而该方法有两个显著缺陷,一是操作流程复杂,而且往往一次 jstack 还不足以定位根因,需要执行多次;二是只能用于诊断在线问题,无法记录历史快照,如果问题已经发生,无法复现的话,往往只能不了了之。



为了解决上述问题,业界领先的 APM 产品已经支持了常态化记录线程/方法栈 CPU开销的持续剖析能力,随时回溯历史快照,对比不同时段的 CPU 热点变化。以阿里云 ARMS 产品为例,典型的 CPU 热点排查思路主要分为以下几步:

1.通过主机/Pod CPU 利用率监控或告警,第一时间发现 CPU 利用率异常飙升现象。

2.通过线程分析监控,快速找到 CPU 消耗最高的线程池,比如 Pressure-CPU*。

image.png

3.通过持续剖析-CPU热点功能,回溯任意时间段内的 CPU 占比火焰图,直接定位到性能瓶颈方法,比如下图中 CPUPressure.runBusiness( ) 方法的 CPU 开销占比高达 99.7%,研发同学定位到具体的业务代码行,就可以快速优化代码解决 CPU 热点问题。

image.png

4.生产系统的方法调用栈更加复杂,ARMS 还支持差分火焰图直观对比不同时间段的 CPU 开销变化,比如应用发布、大促压测等场景,再结合 Copilot 智能诊断给出影响 CPU 变化的关键方法,无需丰富的专家经验也能轻松完成性能优化工作,如下图所示。

image.png

2. JVM 内存性能优化实战

内存(Memory),作为计算机系统中的关键组成部分,不仅影响着程序运行的速度,还决定了多任务处理的能力以及数据访问的效率。从本质上讲,内存是一种临时存储介质,用于存放正在执行的程序及其相关数据,以便CPU能够快速访问。相比于硬盘等长期存储设备,内存具有更高的读写速度,但其容量相对较小且断电后信息会丢失。因此,在计算机体系结构中,合理配置与优化使用内存资源显得尤为重要。

JVM 的内存主要分为堆(Heap)、栈(Stack)、方法区(Method Area)等几个部分。其中,堆用于存放对象实例,而栈则存储了方法调用过程中产生的局部变量及操作数栈等信息。方法区主要用于保存类结构信息如运行时常量池等。其中,堆区域是最容易产生内存热点的地方,因为它直接关联着对象生命周期管理和垃圾收集活动。当 JVM 内存严重不足时,就会抛出 java.lang.OutOfMemoryError 错误,常见的 OOM 类型如下图所示。

image.png

2.1 JVM 内存热点成因分析

常见的 JVM 内存热点产生原因主要包括以下几类,每种原因背后都隐藏着复杂的机制。

1.对象创建过于频繁:如果存在大量短生命周期的对象被频繁地创建与销毁,这将导致垃圾回收器(Garbage Collector, GC)频繁工作以清理不再使用的对象空间。这种情况下,即使GC算法本身效率很高,但由于其执行频率过高,仍然会对系统性能造成显著影响。例如,在循环体内部创建临时变量而不进行复用。为了缓解这一问题,可以考虑使用对象池技术或尽量减少不必要的对象实例化操作。还有一种情况是上游系统请求流量飙升,常见于各类促销/秒杀活动,此时可以考虑添加机器资源,或者做限流降级。

2.大对象分配:当应用程序中申请大对象时(如大型数组),通常会被直接分配到老年代而非新生代区域。虽然这样做可以避免短期内因这些大对象而触发 YoungGC,但如果此类对象数量较多,则可能会迅速填满老年代空间,进而迫使Full GC发生。Full GC会暂停所有用户线程并扫描整个堆区,因此对应用性能的影响尤为严重。针对这种情况,建议评估是否真的需要如此大的数据结构,并探索更高效的数据表示方式。

3.内存泄漏:尽管Java具有自动内存管理功能,但不当的设计模式或编程习惯仍可能导致内存泄露问题。比如,静态集合类持有外部引用、未关闭的数据库连接等都是常见场景。随着时间推移,这些无法被正常回收的对象逐渐积累起来,最终耗尽可用堆空间。解决之道,首先通过一些监控分析工具定界不断增长的内存位置来源,判断内存泄露是发生在堆内还是堆外,如果是堆内可以借助诸如jmap等工具下载内存快照,检查堆内占比高的内存对象,并结合代码分析根因。如果是堆外部分出现了内存稳定增长,此时需要借助一些外部诊断工具,比如 NMT(Native Memory Tracking)等对堆外内存申请情况进行监测,分析可能的原因。

4.不合理的堆大小设置:JVM启动参数中的-Xms(初始堆大小)和-Xmx(最大堆大小)对于控制内存使用至关重要。如果这两个值设置得过低,则可能因为频繁的GC活动而降低程序性能;反之,若设定得过高,则又会浪费宝贵的物理内存资源。理想状态下,应根据实际业务需求及硬件配置情况合理调整这两个参数,一般设置为总内存大小的1/2左右,然后留1/2给非堆部分使用。此外,-XX:NewRatio等选项的设置也很重要,需要基于其去平衡新生代与老年代的比例关系,从而达到最佳性能状态。

5.加载的 class 数目太多或体积太大:永久代(Permanent Generation,JDK 1.8 使用 Metaspace 替换)的使用量与加载到内存的 class 的数量/大小正相关。当加载的 class 数目太多或体积太大时,会导致 永久代用满,从而导致内存溢出报错。可以通过 -XX:MaxMetaspaceSize / -XX:MaxPermSize 上调永久代大小。

2.2 如何排查 JVM 内存热点问题

生产环境需要常态化跟踪 JVM 内存变化,如何第一时间发现 JVM 内存问题,并快速定位止血,整体思路与 CPU 热点优化类似,主要包括以下步骤:

1.通过 JVM 监控/告警发现内存或 GC 异常,分析新生代、老年代、Metaspace、DirectBuffer 等内存变化。

image.png

2.通过持续剖析-内存热点功能,常态化记录每个方法的内存对象分配占比火焰图,比如下图中AllocMemoryAction.runBusiness() 方法消耗了 99.92% 的内存对象分配。

image.png

3.内存快照记录了相关时刻的堆内存对象占用和进程类加载等信息。阿里云 ARMS 提供了一种开箱即用的内存快照白屏化操作功能,让快照创建、获取和分析更加简单便捷。结合阿里云 ATP 分析工具,实现了 JVM 内存对象与引用关系的深入分析和诊断。

image.png

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Kimi K1.5 与 DeepSeek R1:AI 模型的深度对比

文章目录 一、背景介绍二、核心功能对比三、K1.5 使用方法:四、总结 随着人工智能技术的飞速发展,大型语言模型在各个领域都展现出了巨大的潜力。Kimi K1.5 和 DeepSeek R1 作为当前备受关注的两款先进 AI 模型,各自拥有独特的功能和优势。本…

机器学习-生命周期

假如一个用户向银行申请贷款,银行该如何对这个用户进行评估?很明显,银行首先需要调查清楚该用户的资金储备情况和信用历史等,然后再决定是否向其放款。 整个机器学习生命周期如下图所示: 1、定义问题 在使用机器学习中的术语表…

Leetcode:学习记录(二)

按照https://leetcode.cn/circle/discuss/RvFUtj/顺序刷题 零、经验记录 1. 学会画图分析 2. 学会找终止条件 3. 做一道就高质量完成 一、二分算法 0. 总结:大于某个数的第一个数的位置有固定模板,其中要讨论最后一个数小于等于目标数的情况 1. 二…

Elasticsearch AI Assistant 集成 DeepSeek,1分钟搭建智能运维助手

作者:来自阿里云 - 魏子珺 简介: Elasticsearch 新支持 DeepSeek 系列模型,使用 AI 助手,通过自然语言交互,为可观测性分析、安全运维管理及数据智能处理提供一站式解决方案。 一、Elasticsearch AI Assistant 介绍 E…

DeepSeek操作Excel,实现图表自动化生成

案例 让DeepSeek操作Excel,实现图表自动化生成。我们只要用自然语言输入我们的需求(根据哪块单元格区域做什么图表),就可以直接在Excel中自动生成图表。 操作主界面和图表效果 设置接入方式 这里提供了多种接入方式将DeepSeek接…

在 .NET 8/9 中使用 AppUser 进行 JWT 令牌身份验证

文章目录 一、引言二、什么是 JSON Web 令牌?三、什么是 JSON Web 令牌结构?四、设置 JWT 令牌身份验证4.1 创建新的 .NET 8 Web API 项目4.2 安装所需的 NuGet 软件包4.3 创建 JWT 配置模型4.4 将 JWT 配置添加到您的 appsettings.json 中4.5 为 Config…

【R语言】主成分分析与因子分析

一、主成分分析 主成分分析(Principal Component Analysis, PCA)是一种常用的无监督数据降维技术,广泛应用于统计学、数据科学和机器学习等领域。它通过正交化线性变换将(高维)原始数据投影到一个新的坐标系&#xff…

linux下pip下载项目失败

想下载CLIP的项目复现代码的时候,出现问题如下: 于是手动使用 Git 克隆仓库, git clone https://github.com/openai/CLIP.git cd CLIP pip install .ls查看文件如下:(手动克隆git项目成功)

Windows桌面系统管理8:项目实施

Windows桌面系统管理0:总目录-CSDN博客 Windows桌面系统管理1:计算机硬件组成及组装-CSDN博客 Windows桌面系统管理2:VMware Workstation使用和管理-CSDN博客 Windows桌面系统管理3:Windows 10操作系统部署与使用-CSDN博客 Wi…

【JavaScript】实战案例-放大镜效果、图片切换

目录 实现这种图片切换的和放大镜的效果: 第一步:图片的切换 第二步:鼠标经过中等盒子,显示隐藏大盒子 第三步:黑色遮罩盒子跟着鼠标来移动 遮罩层盒子移动的坐标: 总结一下~本章节对我有很大的收获…

windows使用clion运行lua文件,并且使用cjson

需要文件:clion,lua-5.4.2_Win64_bin,lua-5.4.2_Win64_dllw6_lib,lua-cjson-2.1.0.9,mingw64 1,下载安装clion。 2,下载lua windows运行程序 lua官网:http://www.lua.org/download…

人工智能基础之数学基础:01高等数学基础

函数 极限 按照一定次数排列的一列数:“,“,…,"…,其中u 叫做通项。 对于数列{Un}如果当n无限增大时,其通项无限接近于一个常数A,则称该数列以A为极限或称数列收敛于A,否则称数列为发散, 极限值 左…

flink-cdc同步数据到doris中

1 创建数据库和表 1.1 数据库脚本 -- 创建数据库eayc create database if not exists ods_eayc; -- 创建数据表2 数据同步 2.1 flnk-cdc 参考Flink CDC实时同步MySQL到Doris Flink CDC 概述 2.1.1 最简单的单表同步 从下面的yml脚本可以看到,并没有doris中创建…

CUDA兼容NVIDA版本关系

CUDA组成 兼容原则 CUDA 驱动(libcuda.so)兼容类型要求比CUDA新向后兼容无主版本一致,子版本旧兼容需要SASS、NVCC比CUDA老向前兼容提取对应兼容包 向后兼容:新版本支持旧版本的内容,关注的是新版本能否处理旧版本的内容。 向前兼容&#…

要配置西门子G120AX变频器实现**端子启停**和**Modbus RTU(485)频率给定

要配置西门子G120AX变频器实现端子启停和Modbus RTU(485)频率给定,需调整以下关键参数: 1. 端子启停控制 P29652[0]:设置启停信号源 (例:P29652 [0] 722.0 表示用DI0端子作为启动/停止信号&…

撕碎QT面具(3):解决垂直布局的内容显示不全

问题:内容显示不全 解决方案:增加Vertical Spacer,它会把Group Box控件挤上去,让内容显示完全。 结果展示:

LabVIEW 中的 ax - events.llb 库

ax - events.llb 库位于C:\Program Files (x86)\National Instruments\LabVIEW 2019\vi.lib\Platform目录,它是 LabVIEW 平台下与特定事件处理相关的重要库。该库为 LabVIEW 开发者提供了一系列工具,用于有效地处理和管理应用程序中的各种事件&#xff0…

Macos机器hosts文件便捷修改工具——SwitchHosts

文章目录 SwitchHosts软件下载地址操作添加方案切换方案管理方案快捷键 检测 SwitchHosts SwitchHosts 是一款 Mac 平台上的免费软件,它可以方便地管理和切换 hosts 文件,支持多种 hosts 文件格式。 软件下载地址 SwitchHosts 操作 添加方案 添加 …

【算法】双指针(下)

目录 查找总价格为目标值的两个商品 暴力解题 双指针解题 三数之和 双指针解题(左右指针) 四数之和 双指针解题 双指针关键点 注意事项 查找总价格为目标值的两个商品 题目链接:LCR 179. 查找总价格为目标值的两个商品 - 力扣(LeetCode&#x…

嵌入式linux利用标准字符驱动模型控制多个设备方法

一、驱动模型概述 Linux标准字符设备驱动模型基于以下核心组件: 设备号:由主设备号(Major)和次设备号(Minor)组成 cdev结构体:表征字符设备的核心数据结构 文件操作集合:file_operations结构体定义设备操作 sysfs接口:提供用户空间设备管理能力 传统单设备驱动与多设…