如果你的 Java 应用把 CPU 100% 打满,该怎么办呢?

文章目录

  • 如果你的 Java 应用把 CPU 100% 打满,该怎么办呢?
    • CPU 消耗过高分析
      • 上下文切换
      • 运行队列
      • 利用率
    • 定位引起 CPU 过高的代码

如果你的 Java 应用把 CPU 100% 打满,该怎么办呢?

JVM 调优,一般都是在负载压力测试情况下,对于单个节点对外提供服务出现瓶颈时,才会启用性能调优,而 JVM 调优只是其中的一部分。在进行 JVM 调优之前,我一般都会进行 CPU 消耗的分析、内存消耗的分析、磁盘 IO 的分析、网络 IO 的分析以及程序自身问题,在这些指标都正常的情况下,才会转向 JVM 的调优,主要是看内存大小分配是否合理,内存比例是否合理,结合系统特性对垃圾回收器选用是否合理,会对 JVM 进行相关阀值的更改(升带阀值、JIT[Just In Time]),通过打开 JVM 日志收集相关数据,往复这个过程

通常性能瓶颈的表象是资源消耗过多,外部处理系统的性能不足,或者资源消耗不多,但程序的响应速度却仍达不到要求

资源主要消耗在 CPU、文件 IO、网络 IO、以及内存方面,机器的资源是有限的,当某资源消耗过多,通常会造成系统的响应速度慢

资源消耗不多,但程序的响应速度仍达不到要求的主要原因是程序代码运行效率不够高、为充分使用资源或程序结构不合理

下面就结合实际情况来说明,对于 Java 应用,CPU 消耗过高的时,该如何处理?

CPU 消耗过高分析

在 Linux 中,CPU 主要用于中断、内核以及用户进程的任务处理,优先级为 中断>内核>用户进程

上下文切换

每个 CPU(或多核 CPU 中的每核 CPU)在同一时间只能执行一个线程,Linux 采用的抢占式调度
即为每个线程分配一定的执行时间,当到达执行时间、线程中有 IO 阻塞或高优先级线程要执行时,Linux 将切换执行的线程,在切换时要存储目前线程的执行状态,并恢复要执行的线程的状态,这个过程就称为上下文切换
对于 Java 应用,典型的实在进行文件 IO 操作、网络 IO 操作、锁等待或线程 Sleep 时,当前线程会进入阻塞或休眠状态,从而出发上下文切换,上下文切换过多或造成内核占据较多的 CPU 使用,似的应用的响应速度下降

运行队列

每个 CPU 都维护了一个可运行的线程队列
运行队列值越大,意味着线程会消耗越长的时间才能完成
建议控制每个 CPU 核上的运行队列为 1~3 个

利用率

CPU 利用率为 CPU 在用户进程内核中断处理IO等待以及空闲五个部分使用百分比,这五个值用来分析 CPU 消耗情况的关键指标。
建议用户进程的 CPU 消耗/内核的 CPU 消耗的比率在 65%~70%/30%~35% 左右

top命令

如果你的 Java 应用把 CPU 100% 打满,该怎么办呢?_第1张图片

top命令的输出可以分为两个部分:前半部分是系统统计信息,后半部分是进程信息。

前半部分信息:

第一行:系统当前时间、系统运行时间、当前登录用户数。load average 表示系统的平均负载,即任务队列的平均长度,分别表示 1 分钟、5 分钟、15 分钟

第二行:进程统计信息,分别有正在运行的进程数、睡眠进程数、停止的进程数、僵尸进程数

第三行:CPU统计信息,us 表示用户空间CPU占用率、sy 表示内核空间CPU占用率、ni 表示用户进程空间改变过优先级的进程 CPU 的占用率、id 表示空闲 CPU 占用率、wa 表示在进程执行过程中等待 IO 所占的百分比、hi 表示硬件中断所占的百分比、si 表示软件终端所占的百分比

可在进入top试图后按 1,就会按核来现实消耗情况

如果你的 Java 应用把 CPU 100% 打满,该怎么办呢?_第2张图片

在top视图中按 shift+h,可按线程查看 CPU 的消耗状况

如果你的 Java 应用把 CPU 100% 打满,该怎么办呢?_第3张图片

此时的 PID 即为线程 ID,其后的 %CPU 表示该线程所消耗的 CPU 占比

定位引起 CPU 过高的代码

当 CPU 消耗严重时,主要体现在 us、sy、wa 或 hi 的值变高,wa 的值时 IO 等待造成的;hi 的值变高主要因为硬件中断造成的,例如网卡接受数据频繁的状况
对于 Java 应用而言,CPU 消耗严重主要体现在 us、sy 两个值上

当 us 值过高时,表示运行的应用消耗了大部分的 CPU,在这种情况下,对于 Java 应用而言,最重要的为找到具体消耗 CPU 的线程所执行的代码,可采用如下步骤:

  • 通过 linux 提供的命令找到消耗 CPU 严重的线程及其 ID,将此线程 ID 转化为十六进制的值
  • 通过kill -3 [javapid]jstack的方式 dump 出应用的 java 线程信息
  • 通过之前转化的十六进制的值找到对应的 nid 值的线程
  • 该线程即为消耗 CPU 的线程,通过 dump 文件中的代码块,即可定位实际有问题的代码

你可能感兴趣的:(Java基础,java,linux,top,jstack)