TECHNOLOGY_FRONTIER

>> 已收录 ${postCount} 项技术方案

性能测试十:性能分析与调优(性能分析方法、CPU、MEM)

一、性能分析


 1.1 性能分析的任务


不是寻找问题,而是辨别问题,或者说是辨别哪些问题是重要的。

1.2 性能分析的挑战


从什么地方开始分析?收集哪些数据?如何分析数据?

性能领域知道的越多,不知道的就越多

1.3 异常现象分类


异常一:TPS波动

波动现象1:TPS有明显的大幅波动,不稳定。例如TPS轨迹缓慢下降,缓慢上升后骤降,呈瀑布型,呈矩形,分时间段有规律的波动,无规律的波动等。这些TPS的波动轨迹反映出被测试的性能点存在性能瓶颈,需要性能测试工程师与开发工程师查找性能瓶颈的原因。

波动现象2:TPS轨迹比较平稳,但是也存在波动现象。该类波动不明显,很难直接确定是否存在性能瓶颈。

TPS波动科学分析

TPS分析图中涉及到了4个重要的参数,最大值平均值最小值标准差值,平均值和标准差是衡量TPS是否稳定的重要因子。
TPS平均值是在场景执行过程中,被测系统在指定时间段内的平均每秒处理的事务数量
TPS标准差是根据数理统计的概念得来,反映被测系统的波动情况,标准差越小,说明波动越小,系统越稳定

也就是说对于一组数值与平均数分散开的程度,越分散表示与平均数相差越大,标准差越大,TPS波动范围 = TPS标准差/ TPS平均值×100%
可接受波动范围
接口: 5%+/-3%
Web: 4%+/-2%

 

异常二:性能不达标
测试指标不达标,包括TPS、ART、事物成功率、资源使用率
 
异常三:集群节点负载不均衡
组件各个节点CPU使用率相差>10%
 
异常四:负载拐点异常
随着并发用户数增加,TPS下降或波动。
 

1.4 性能分析方法


1.4.1 性能分析准则


从上至下

RBIRapid Bottleneck Identify)方法是Empirix公司提出的一种用于快速识别系统,性能瓶颈的方法。该方法基于以下一些事实:
1. 发现的80%系统的性能瓶颈都由吞吐量制约;
2. 并发用户数和吞吐量瓶颈之间存在一定的关联;
3. 采用吞吐量测试可以更快速定位问题。
通过不断增加并发用户数和吞吐量,观察系统的性能表现,确定是由并发还是由吞吐量引发的性能表现限制,然后从网络、数据库、应用服务器和代码本身4个环节确定系统性能具体的瓶颈。
分析系统的瓶颈点遵循的规则如下:
- 操作系统资源消耗:   CPU、Memory、Disk I/O、Network I/O。
- 中间件指标:      线程池(Thread Pool)、数据库连接池(JDBC)、JVM(GC/FULL GC/堆大小)。
- 数据库指标:      效率低下SQL、锁等待/死锁、缓存命中率、会话、进程等。
- 应用:         方法耗时、算法、同步和异步、缓存、缓冲。
- 压力机:        压力机资源消耗,一般情况下,压力机成为瓶颈的可能性非常低。PTS压力机有保护和调度机制不用单独关注。

 

从局部到整体

具体参照分层分析方法
 

1.4.2 分层分析


 分层分析一般需要对系统的应用架构以及部署架构的层次非常熟悉,需要熟知请求的处理链过程。

  • 分层分析一般需要对每一层建立checklist(检查清单)​,然后按照每一层的checklist逐一进行分析。
  • 通过分层分析来排查问题的效率虽然较低,但是往往能发现更多的性能问题。
  • 分层分析可以自上而下,也可以自下而上。

对于一个应用系统,常见的分层分析思路如图
  • 首先排除压力机性能情况,包括CPU、内存
  • 网络分发。如CDN,可以降低网络拥塞。
  • Web服务。除了其自身外,也包括Web Cache。
  • 应用程序服务。除了其自身外,也包括应用层Cache和同外部系统的交互。
  • Data(DB)。即数据或数据库。

 

1.4.3 科学论证


 科学论证是指通过一定的假设和逻辑思维推理来分析性能问题,一般包括发现问题、问题假设、预测、试验论证、分析这5个步骤,如图

1.发现问题: 指通过性能采集和监控,发现性能瓶颈或者性能问题,比如并发用户数增大后TPS并不增加、每台应用服务器的CPU消耗相差特别大等。

2.问题假设: 指根据自己的经验判断,假设是某个因素导致出现了瓶颈和问题。

3.预测: 指根据问题假设,预测可能出现的一些现象或者特征。

4.试验论证: 根据预测,通过试验去检查预期可能出现的现象或者特征。

5.分析: 根据获取到的实际现象或者特征进行分析,判断假设是否正确,如果不正确,就重新按照这个流程进行分析论证。

 

 示例

 

 1.4.4  问题追溯与归纳总结


问题追溯指的是根据问题去追溯最近系统或者环境发生的变化,一般适用于已上线生产系统的版本发布或者环境变动导致的性能问题。

问题追溯是通过不断向下追溯问题和根据问题描述去逐步排查可能导致问题的原因。
问题追溯的步骤一般如下
1.是怎么觉得运行的系统或软件有性能问题的?
2.是用户反馈的吗?感觉系统或者软件很卡顿?
3.问题能用具体的性能指标描述吗?打开网页响应时间很慢?
4.问题影响其他系统吗?是不是独立系统?
5.最近有什么变动吗?代码有变动吗?数据库表有变动吗(新建表或索引)?服务器有硬件变动吗?网络有变动吗?配置有变动吗?
6.是下游别的系统造成的响应吗?下游别的系统最优有发布吗?
归纳总结指在出现某种性能瓶颈或者性能问题时,根据以往经验逐一排查
 

二、性能调优


 2.1 稳定性与性能的选择


衡量代码质量的标准是可读性、可维护性、可扩展性,但性能优化有可能会违背这些特性,比如为了屏蔽实现细节与使用方式,我们会可能会加入接口层(虚拟层),这样可读性、可维护性、可扩展性会好很多,但是额外增加了一层函数调用,如果这个地方调用频繁,那么也是一笔开销。

这种有损代码质量的优化,应该放到最后,不得已而为之,同时写清楚注释与文档。
 

2.2 获取单进程系统瓶颈


搭建Mock程序,获取单台压力机线程数、系统资源、性能最大值。用于排除压力机、网络等因素影响

注意

mock程序部署机器物理配置最好能和压力机对等(对等时,至少部署两台),如果不能对等,部署多台,以排除部署机器的瓶颈;
通过逐步增加线程数,观察平均响应时间和TPS,随着线程数的增加,TPS很难上升,平均响应时间明显增加的情况下,基本可以说明已经达到压力机的瓶颈,记下此时的线程数,在压测时,单台压力机最大线程数不宜超过该线程数,否则压测结果中,TPS和平均响应时间不准,压测结果不准确。
 

2.3 CPU对性能影响


 2.3.1 CPU负载


 

# top
load average: 29.17, 29.24, 29.55

 第一个值:1分钟CPU负载   表示最近的暂时现象

 第二个值:5分钟CPU负载

 第三个值:15分钟CPU负载  表示是持续现象,并非暂时问题

  如果laod15较高,laod1较低,可以认为是情况有所好转
理想情况下一个核心被一个进程占用,如果你是4个核心(逻辑CPU个数),那么跑4个进程,此时Load是4但是也不高,如果你只有2个核心,依然跑4个进程,这就意味着有一半进程在某一个时刻抢不到CPU,这时候Load还是4,如果是短期状态还无所谓,如果长期是这个状态你就要注意了
 
CPU负载高利用率低
说明等待执行的任务很多,但是通常任务多CPU使用率也会比较高,如果低就说明CPU根本没工作,哪些很多的任务处于等待状态,可能进程僵死了。(:可以通过命令 ps –axjf 查看是否存在D状态的进程,该状态时不可中断的睡眠状态,这种状态无法被KILL)
而有时候你通过top命令也看不出来,只能显示LOAD高,但是没有哪个进程的CPU使用率明显高,你可以通过 ps –ux 来查看。
CPU利用率高负载低
说明任务少,但是任务执行时间长,有可能是程序本身有问题,如果没有问题那么计算完成后则利用率会下降。
 

2.3.2. CPU使用率来源


 

来源:Linux 通过 /proc 虚拟文件系统,向用户空间提供了系统内部状态的信息,而 /proc/stat 提供的就是系统的CPU任务统计信息

 

# cat /proc/stat | grep ^cpu
//
结果分析:从左往右一共 11 列 CPU 编号:        第一行是 CPU 的累加 user(us):       用户态 CPU 的时间,不包括下面的 nice 时间,但包括了 guest 时间 nice(ni):       低优先级用户态 CPU 的时间,就是进程的 nice 值被调整为 1-19 之间时的 CPU 时间;注意 nice 可取值范围是 -20 到 19,数值越大,优先级反而越低 system(sys):     内核态 CPU 的时间 idle(id):       空闲时间,它不包括等待 I/O 的时间(iowait) iowait(wa):      等待 I/O 的 CPU 时间 irq(hi):        处理硬中断的 CPU 时间 softirq(si):     处理软中断的 CPU 时间 steal(st):       当系统运行在虚拟机中的时间,被其他虚拟机占用的 CPU 时间 guest:          通过虚拟化运行其他操作系统的时间,就是运行虚拟机的 CPU 时间 guest_nice(gnice): 以低优先级运行虚拟机的时间

 

2.3.3 CPU使用率


 节拍率

  • 为了维护 CPU 时间,Linux 通过事先定义的节拍率(内核中表示为 HZ),触发时间中断,并使用全局变量 Jiffies 记录了开机以来的节拍数
  • 每发生一次时间中断,Jiffies 的值 就加 1。
  • 节拍率 HZ 是内核的可配选项,可以设置为 1002501000
  • 不同的系统可能设置不同数值,你可以通过查询 /boot/config 内核选项来查看它的配置值
  • 比如在我的系统中, 节拍率设置成了 1000,也就是每秒钟触发 1000 次时间中断。
# grep 'CONFIG_HZ=' /boot/config-$(uname -r)

用户空间节拍率

  • 因为节拍率 HZ 是内核选项,所以用户空间程序并不能直接访问
  • 为了方便用户空间程序,内核还提供了一个用户空间节拍率 USER_HZ
  • 它总是固定为 100,也就是 1/100
  • 这样,用户空间程序并不需要关心内核中 HZ 被设置成了多少,因为它看到的总是固定值 USER_HZ

 

CPU使用率计算公式

CPU使用率通常指处理器在特定时间内执行非空闲任务的时间占比,反映其忙碌程度。计算方式如下:

1.基础公式

 

2.实际监控中的采样方法

 

3.多核CPU注意事项

  • 若系统有N个逻辑核心,理论上最大使用率为 N×100%N×100%(如4核可达400%)。监控工具可能显示为总使用率或平均每核使用率。
  • 性能分析工具给出的都是间隔一段时间的平均 CPU 使用率,所以要注意间隔时间的设置

 

2.3.4 CPU使用率对性能影响


 CPU>70%使用率对性能影响

  • 任务排队延迟增加,响应变慢。

  • 系统可能频繁上下文切换,导致额外开销。

  • 若持续接近100%,可能触发降频或过热保护(硬件层面

 

2.3.5 CPU上下文切换


什么是CPU上下文切换

上下文切换(Context Switching 是CPU从执行一个进程/线程切换到另一个进程/线程时,必须保存当前任务状态如寄存器、程序计数器、内存页表等),并加载新任务状态的过程。主要分为三类:

  1. 进程上下文切换:不同进程间的切换,需切换虚拟内存等资源,开销最大

  2. 线程上下文切换:同一进程内的线程切换,共享内存空间,仅需切换私有数据(如寄存器),开销较小

  3. 中断上下文切换:硬件中断(如网卡数据到达)触发,需暂停当前任务处理中断,要求快速完成

 
全局上下文统计
#vmstat 5 5   //5s采样 每隔 5s 输出一次结果
procs -------memory-------    --swap--  --io---  --system--  ----cpu----
r b  swpd   free  buff cache   si so    bi  bo   in   cs     us sy id wa
1 0  62792  3460  9116 88092   6  30    189 89   1061 569    17 28 54  2
0 0  62792  3400  9124 88092   0  0     0   14   884  434    4  14 81  0
0 0  62792  3400  9132 88092   0  0     0   14   877  424    4  15 81  0
1 0  62792  3400  9140 88092   0  0     0   14   868  418    6  20 74  0
1 0  62792  3400  9148 88092   0  0     0   15   847  400    9  25 67  0

//procs:
r: 在运行队列中等待的进程数                running or Runnable,如CPU为4C,r为8,就存在CPU竞争
b: 在等待io的进程数                     locked

//内存memoy: swpd:现时可用的交换内存(单位KB) free:空闲的内存(单位KB) buff: 缓冲器中的内存数(单位:KB) cache:被用来做为高速缓存的内存数(单位:KB)
//swap交换页面 si: 从磁盘交换到内存的交换页数量,单位:KB/秒 swap-input so: 从内存交换到磁盘的交换页数量,单位:KB/秒 swap-output
//io块设备: bi: 发送到块设备的块数,单位:块/秒 block-input bo: 从块设备接收到的块数,单位:块/秒 block-output
//system系统 in: 每秒的中断数,包括时钟中断 interrupt cs: 每秒的环境(上下文)转换次数    context switch

//cpu中央处理器 us:用户进程使用的时间 以百分比表示 sy:系统进程使用的时间 以百分比表示 id:中央处理器的空闲时间   以百分比表示

 

进程/线程上下文统计

# pidstat -wt -u 3 3   //每3s输出一次结果,共输出3次
结果分析
- cswch:           //每秒自愿上下文切换
- nvcswch:        //每秒非自愿上下文切换的次数 


自愿上下文切换
- 进程无法获取所需自愿,导致的上下文切换 - 栗子:I/O、内存等系统资源不足时,就会发生

非自愿上下文切换
- 非自愿上下文切换,则是指进程由于时间片已到等原因,被系统强制调度,进而发生的上下文切换 - 栗子:大量进程都在争抢CPU时,就容易发生非自愿上下文切换,CPU成为瓶颈
pidstat默认显示进程级别的指标数据
-t 参数它可以显示与选定任务关联的线程的统计信息
-w 选项,每3s输出一次结果,共输出3次
-u 输出 CPU 使用情况

 

中断相关统计

# cat /proc/interrupts      //显示每个CPU核心的中断次数
- 高频中断可能间接导致上下文切换增多(如网络包处理)。
- 栗子:中断升高是多任务调度问题,说明CPU被中断处理程序占用,需通过/pro/interrupts文件来分析中断类型

备注
/proc/interrupts 是只读文件,/proc实际上是 Linux 的一个虚拟文件系统,用于内核空间与用户空间之间的通信

 

2.3.6 上下文切换对性能影响


 1. 直接开销
  • CPU时间浪费:保存和恢复寄存器、内存页表等操作消耗CPU周期。

  • 缓存失效:切换后CPU缓存(L1/L2/L3)可能失效,降低后续指令执行效率。

2. 间接性能问题

  • 高并发场景:线程/进程过多时,频繁切换导致吞吐量下降。示例:1万个线程竞争CPU,实际执行时间可能被大量切换开销淹没。

  • 锁竞争:线程因锁阻塞会触发自愿切换,加剧延迟。

  • 实时性下降:高频切换可能破坏低延迟任务的响应时间。

3. 性能问题诊断

  • 症状

  • CPU使用率高但系统吞吐量低。

  •  vmstatr列(就绪队列)持续大于CPU核心数。

  •  pidstat显示某些进程的cswch/snvcswch/s异常高。

  • 阈值参考

  • 单核CPU:若上下文切换 > 1万次/秒,可能存在性能问题。   

  • 多核系统:需结合核心数评估(如8核系统,总切换量可能达数万次/秒)。

4.分析步骤

  • 通过 vmstat 确认系统的当前的上下文切换(cs)、中断次数(in)、就绪队列(r)、CPU 使用率(us、sy
  • 若上下文切换次数和 CPU 使用率过高,通过 pidstat 查看是哪个进程或线程的切换次数过高,CPU 使用率过高
  • 然后确认是自愿上下文切换还是非自愿上下文切换,从而深入分析是否存在其他系统瓶颈问题
  • 若中断次数过高,通过 /proc/interrupts 分析是哪种中断类型 

 

2.4 内存对性能影响


2.4.1 物理内存(Physical Memory)

# free -h
              total       used       free      shared  buff/cache   available
Mem:          62G         15G        3.2G      1.5G    43G          45G
Swap:         8G          0B         8G
  • 实际硬件RAM,供进程和内核直接使用。
  • buff/cache:内核缓冲区(Buffer)和页缓存(Page Cache),用于加速磁盘I/O。

  • available:系统当前可分配给进程的内存(包含缓存可回收部分

 

2.4.2 物理内存对性能影响


内存充足时(Available > 20%)

  • 系统运行流畅,缓存机制提升I/O性能(如频繁读取的文件缓存到内存
  • 进程可快速分配内存,响应时间短

内存不足时(Available < 10%)

  • OOM Killer触发:内核强制终止占用内存最多的进程(日志见/var/log/messages
  • Swap频繁使用:磁盘I/O增加,系统响应延迟明详增加(可通过vmstat 1 观察 si / so列
  • 进程卡顿:内存分配失败导致进程挂起或崩溃(如Java应用的OutOfMemoryError

极端场景

  • 内存泄漏:进程持续申请内存但不释放,最终耗尽系统资源。即进程的RES(常驻内存)持续增长,重启后恢复
  • 内存碎片化:物理内存被分割成小块,无法满足大内存分配需求(常见于长期运行的服务
  • 缓存占用过高buff/cache占用大量内存,但Available仍充足;可能挤占应用内存,但可通过内核自动回收缓解。
  • 大页内存配置不当:应用(如数据库)因未配置HugePages导致内存管理开销大; TLB(Translation lookaside Buffer)未命中率升高性能下降。
备注:
CPU每次访问虚拟内存,虚拟地址都必须转换为对应的物理地址。从概念上说,这个转换需要遍历页表,页表是三级页表,就需要3次内存访问。就是说,每次虚拟内存访问都会导致4次物理内存访问。
简单点说,如果一次虚拟内存访问对应了4次物理内存访问,肯定比1次物理访问慢,这样虚拟内存肯定不会发展起来。
幸运的是,有一个聪明的做法解决了大部分问题:现代CPU使用一小块关联内存,用来缓存最近访问的虚拟页的PTE。这块内存称为translation lookaside buffer(TLB)。

 

2.4.3 虚拟内存(Virtual Memory)


什么是虚拟内存

内存管理系统是操作系统中最为重要的部分,因为系统的物理内存总是少于系统所需要的内存数量。

虚拟内存就是为了克服这个矛盾而采用的策略,使用磁盘作为RAM的扩展,通过在各个进程之间共享内存而使系统看起来有多于实际内存的内存容量。

  • 操作系统抽象出的逻辑内存模型,每个进程拥有独立的虚拟地址空间,可超出物理内存容量。
  • 每个进程通过虚拟地址空间独立访问内存,避免直接操作物理内存,确保隔离性和安全性。
  • 物理内存仅分配进程实际使用的部分,虚拟内存通过分页机制(Paging)动态管理映射。
  • 当物理内存不足时,不活跃的内存页被换出到磁盘交换空间(Swap Space),腾出物理内存供急需的进程使用。
  • 每个进程的虚拟内存布局可通过 pmap/proc/<PID>/maps查看。

虚拟内存的优势

  • 进程隔离:防止进程间非法内存访问。
  • 大地址空间:进程可操作超出物理内存容量的虚拟地址(如64位系统支持巨大地址空间
  • 高效利用内存:通过共享库(如glibc)和写时复制(Copy-on-Write)减少冗余占用。
  • 延迟分配:物理内存仅在进程实际写入时分配(如malloc() 分配虚拟地址,首次访问时触发缺页分配物理页

 

2.4.4 Swap空间


  • 磁盘上的虚拟内存扩展,当物理内存不足时,将不活跃的页换出到Swap
  • 使用 swapon -s 查看当前 Swap设备
  • 使用 vmstat 1 3 查看 Swap使用情况si /so 

 

2.4.5 内核内存


  • 用于内核数据结构(如进程描述符、网络栈、Slab分配器等
  • 地址转换(MMU与页表)内存管理单元(MMU)- 硬件组件,将进程的虚拟地址转换为物理地址; 页表(Page Table)- 内核维护的数据结构,记录虚拟页到物理页帧的对应关系。若目标页不存在物理内存(触发缺页中断),内核从磁盘加载数据。
  • 分页与交换分页 - 物理内存与虚拟内存被均分为固定大小的页(通常4KB); 页面置换 - 当物理内存不足时,页面置换算法(如LRU)选择不活跃的页换出到交换区,后续访问再换入(Page In/Out
  • 内存保护权限控制 - 页表条目包含读写执行权限,防止进程越界访问  ;内核/用户空间隔离 - 用户进程无法直接访问内核空间虚拟地址,需通过系统调用。
  • 通过slabtop /proc/meminfo 中的Slab字段监控

 

2.4.6 MEM使用率

 1 [root@localhost ~]# cat /proc/meminfo   所有命令最终都是通过该文件获取系统内存使用情况的
 2 MemTotal:        3714660 kB
 3 MemFree:         3177016 kB
 4 MemAvailable:    3242452 kB
 5 Buffers:            2708 kB
 6 Cached:           255136 kB
 7 SwapCached:            0 kB
 8 Active:           141640 kB
 9 Inactive:         178340 kB
10 Active(anon):      51844 kB
11 Inactive(anon):    19408 kB
12 Active(file):      89796 kB
13 Inactive(file):   158932 kB
14 Unevictable:           0 kB
15 Mlocked:               0 kB
16 SwapTotal:       2097148 kB
17 SwapFree:        2097148 kB
18 Zswap:                 0 kB
19 Zswapped:              0 kB
20 Dirty:                 0 kB
21 Writeback:             0 kB
22 AnonPages:         62136 kB
23 Mapped:            40020 kB
24 Shmem:              9116 kB
25 KReclaimable:      40960 kB
26 Slab:              95164 kB
27 SReclaimable:      40960 kB
28 SUnreclaim:        54204 kB
29 KernelStack:        4752 kB
30 PageTables:         1444 kB
31 SecPageTables:         0 kB
32 NFS_Unstable:          0 kB
33 Bounce:                0 kB
34 WritebackTmp:          0 kB
35 CommitLimit:     3954476 kB
36 Committed_AS:     185864 kB
37 VmallocTotal:   34359738367 kB
38 VmallocUsed:       54176 kB
39 VmallocChunk:          0 kB
40 Percpu:            48128 kB
41 HardwareCorrupted:     0 kB
42 AnonHugePages:     14336 kB
43 ShmemHugePages:        0 kB
44 ShmemPmdMapped:        0 kB
45 FileHugePages:         0 kB
46 FilePmdMapped:         0 kB
47 CmaTotal:              0 kB
48 CmaFree:               0 kB
49 Unaccepted:            0 kB
50 HugePages_Total:       0
51 HugePages_Free:        0
52 HugePages_Rsvd:        0
53 HugePages_Surp:        0
54 Hugepagesize:       2048 kB
55 Hugetlb:               0 kB
56 DirectMap4k:      139072 kB
57 DirectMap2M:     3006464 kB
58 DirectMap1G:     3145728 kB
内存使用率 = Memtotal - Memfree - cached - buffers)/ Memtotal  * 100%   ;(3714660 - 3177016 - 255136 - 2708)/ 3714660 * 100% = 7.53%

 

2.4.7 MEM问题排查方法


全局内存状态分析

实时查看数据
free
-h # 查看总体内存使用 top # 实时监控进程内存(按`M`按内存排序)
vmstat 1 5        # 每秒输出一次,共5次 关注swpd(已用Swap)、si(Swap In)、so(Swap Out)、free(空闲内存)

历史内存数据
sar -r 1 3        #每秒采样内存,共三次
sar -B 1 3        #查看分页统计(缺页异常、Swap活动)

 

进程级内存分析

定位高内存进程
ps
aux --sort=-%mem | head -n 10         # 按内存使用排序显示前10进程 pmap -X <PID>                # 显示进程详细内存分配(需安装procps)

查看进程内存映射
pmap -X <PID>                     # 显示进程详细内存分配(需安装procps)

检测内存泄漏工具
valgrind --leak-check=full ./your_program    # 适用于C/C++程序
jstak -gctil <PID> 1000               # 适用于java ;每秒输出GC统计,观察老年代占用

 

内核与缓存分析

详细信息
cat /proc/meminfo |grep -E 'MemTotal|MemFree|Buffers|Cached|Swap|Slab'

Slab内存分析
slabtop -o                  # 按占用排序显示Slab缓存

手动释放缓存:
echo 3 > /proc/sys/vm/drop_caches    # 释放PaageCache、Slab等(不影响进程)

 

Swap优化与配置

调正Swap使用倾向:
sysctl vm.swappiness=10                # 默认60,值越低越倾向保留物理内存(临时生效)
永久生效写入 /etc/sysctl.conf

禁用或扩容Swap:
swapoff -a                           # 禁用所有Swap分区
dd if=/dev/zero of=/swapfile bs=1G count=8    # 创建8G Swap文件
mkswap /swapfile && swapon /swapfile

 

JVM内存分析

方法一:使用JDK工具jmap获取dump文件
# ps -ef|grep java                                 # 获取javaGC进程
# jmap -dump:format=b,file=/path/to/dumpfile.hprof <PID>    # 其中 /path/to/dumpfile.hprof 是dump文件保存的路径,PID 是进程的 ID


方法二:在应用程序中编写代码获取线程dump文件
 应用程序中编写代码获取线程 dump 文件,可以使用 Thread 类中的静态方法 getAllStackTraces() 获取当前运行的所有线程的堆栈信息,并将这些信息输出到文件中,代码如下:
 
ThreadInfo[] threadInfos = ManagementFactory.getThreadMXBean().dumpAllThreads(true, true);
PrintWriter pw = new PrintWriter(new FileWriter("/path/to/dumpfile.txt"));
for (ThreadInfo threadInfo : threadInfos) {
   pw.print(threadInfo.toString());
}
pw.close();
# 其中 /path/to/dumpfile.txt 是dump文件保存的路径
 
  方法三配置OOM后自动生成dump文件
-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=D:\tmp
# 模拟OOM错误,出发产生dump文件
private static Map<String, String> map = new HashMap<>();
@RequestMapping("/oom")
public String oom() throws Exception {
    for (int i = 0; i < 100000; i++){
        map.put("key" + i, "value" + i);
    }
    return "oom";
}

 

dump文件分析

将Linux文件移动至Windows

步骤一 压缩:# tar -zcvf newdump.tar.gz user.dump
步骤二 分割:# split-b 100M newdump.tar.gz -d newdump_offshoot.tar.gz
步骤三 合并:cmd进入windows控制台
      # copy
/b 分割文件1 + 分割文件2 + .... 合并文件名
MAT工具分析dump文件
File → Open → Heap → Dump,查看Leak Suspects、TOP Consumers

 

 

posted on 2025-03-25 14:10  王元安  阅读(336)  评论(0)    收藏  举报