最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Java應(yīng)用CPU占用過高問題的快速定位和解決方法

 更新時(shí)間:2025年11月06日 09:28:29   作者:???傀儡師  
本文介紹了快速定位和解決Java應(yīng)用CPU占用過高問題的標(biāo)準(zhǔn)流程,并通過一個(gè)實(shí)際案例演示,核心思想是通過進(jìn)程、線程、線程棧和源代碼的逐步排查,最終定位到問題代碼,需要的朋友可以參考下

在這里插入圖片描述

問題背景

在生產(chǎn)環(huán)境中,我們經(jīng)常會(huì)遇到Java應(yīng)用突然CPU占用飆升的情況。這種問題如果不及時(shí)解決,可能會(huì)耗盡系統(tǒng)資源,影響整個(gè)應(yīng)用的穩(wěn)定性。本文將介紹一套快速定位和解決Java應(yīng)用CPU占用過高問題的標(biāo)準(zhǔn)流程,并通過一個(gè)實(shí)際案例演示。

排查工具與核心思路

核心思路:進(jìn)程 → 線程 → 線程棧 → 源代碼

主要工具:

top:查看系統(tǒng)進(jìn)程資源占用情況

top -Hp:查看指定進(jìn)程下的線程資源占用

printf:將線程ID轉(zhuǎn)換為十六進(jìn)制

jstack:獲取Java進(jìn)程的線程堆棧信息

grep:過濾匹配的線程堆棧信息

詳細(xì)排查步驟

步驟1:定位CPU占用最高的進(jìn)程

使用top命令查看系統(tǒng)進(jìn)程資源占用情況:

top

重點(diǎn)關(guān)注%CPU列,找到CPU占用比例最高的進(jìn)程,并記錄其PID(進(jìn)程ID)。

步驟2:定位進(jìn)程內(nèi)CPU占用最高的線程

使用以下命令查看指定進(jìn)程內(nèi)所有線程的CPU占用情況:

top -Hp [PID]

其中[PID]是上一步記錄的進(jìn)程ID。找到CPU占用最高的線程,記錄其線程ID。

步驟3:轉(zhuǎn)換線程ID為十六進(jìn)制

Java的線程堆棧信息中的線程ID是以十六進(jìn)制表示的,需要轉(zhuǎn)換:

printf "0x%x" [線程ID]

記錄轉(zhuǎn)換后的十六進(jìn)制線程ID。

步驟4:定位問題代碼

使用jstack獲取線程堆棧,并結(jié)合grep過濾出問題線程的堆棧信息:

jstack [PID] | grep [十六進(jìn)制線程ID] -A 10

-A 10參數(shù)表示顯示匹配行后的10行內(nèi)容,這通常能包含足夠的方法調(diào)用信息來定位問題代碼。

實(shí)戰(zhàn)案例演示

場景描述

某Java應(yīng)用在壓測期間CPU占用率突然飆升到200%以上,需要快速定位問題原因。

排查過程

1. 定位高CPU占用進(jìn)程

top

輸出結(jié)果:

PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND12345 appuser 20 0 12.3g 2.1g 1.2g R 215.6 6.7 10:30.25 java

發(fā)現(xiàn)PID為12345的Java進(jìn)程CPU占用率高達(dá)215.6%。

2. 定位進(jìn)程內(nèi)高CPU占用線程

top -Hp 12345

輸出結(jié)果:

PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND12367 appuser 20 0 12.3g 2.1g 1.2g R 99.8 6.7 8:45.12 java12368 appuser 20 0 12.3g 2.1g 1.2g R 99.7 6.7 8:44.98 java

發(fā)現(xiàn)線程ID為12367和12368的兩個(gè)線程CPU占用率都很高。

3. 轉(zhuǎn)換線程ID為十六進(jìn)制

printf "0x%x" 12367

輸出:0x304f

printf "0x%x" 12368 

輸出:0x3050定位問題代碼

jstack 12345 | grep "0x304f" -A 10

輸出結(jié)果:

"Thread-0" #20 prio=5 os_prio=0 tid=0x00007f8a1410c800 nid=0x304f runnable [0x00007f8a0c7f7000]
   java.lang.Thread.State: RUNNABLE
    at com.example.ExampleService.processData(ExampleService.java:45)
    at com.example.ExampleService$$Lambda$1.run(Unknown Source)
    at java.lang.Thread.run(Thread.java:750)

同樣檢查另一個(gè)高CPU線程:

jstack 12345 | grep "0x3050" -A 10

輸出結(jié)果:

"Thread-1" #21 prio=5 os_prio=0 tid=0x00007f8a1410d000 nid=0x3050 runnable [0x00007f8a0c6f6000]
   java.lang.Thread.State: RUNNABLE
    at com.example.ExampleService.processData(ExampleService.java:45)
    at com.example.ExampleService$$Lambda$1.run(Unknown Source)
    at java.lang.Thread.run(Thread.java:750)

問題分析與解決
兩個(gè)高CPU線程都指向ExampleService.java的第45行。查看源代碼:

public class ExampleService {
    public void processData() {
        while (true) {
            // 第45行 - 空循環(huán),沒有退出條件
            // 這里應(yīng)該是處理業(yè)務(wù)的邏輯,但誤寫成了死循環(huán)
        }
    }
}

問題原因:代碼中誤寫了死循環(huán),導(dǎo)致線程持續(xù)占用CPU資源。

解決方案:
添加合理的循環(huán)退出條件
在循環(huán)體內(nèi)添加適當(dāng)?shù)膕leep或等待邏輯
修復(fù)后的代碼:

public class ExampleService {
    public void processData() {
        while (!Thread.currentThread().isInterrupted()) {
            // 業(yè)務(wù)處理邏輯
            processBusiness();
            
            // 添加適當(dāng)?shù)男菝?,避免空轉(zhuǎn)
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
                break;
            }
        }
    }
}

常見CPU高占用場景
死循環(huán):如案例所示,缺少退出條件的循環(huán)
頻繁GC:大量對(duì)象創(chuàng)建和回收
復(fù)雜算法:遞歸過深或計(jì)算復(fù)雜度高的操作
鎖競爭:線程頻繁嘗試獲取鎖
無限遞歸:缺少基準(zhǔn)情況的遞歸調(diào)用

預(yù)防措施
代碼審查:重點(diǎn)關(guān)注循環(huán)和遞歸邏輯
性能測試:定期進(jìn)行壓力測試,監(jiān)控CPU使用情況
監(jiān)控告警:建立完善的監(jiān)控體系,設(shè)置CPU使用率閾值告警
代碼規(guī)范:避免在循環(huán)內(nèi)進(jìn)行不必要的復(fù)雜計(jì)算

總結(jié)
通過top → top -Hp → printf → jstack + grep這一套組合拳,我們可以快速定位到導(dǎo)致CPU占用過高的具體代碼位置。掌握這套排查流程對(duì)于Java開發(fā)者來說至關(guān)重要,能夠在生產(chǎn)環(huán)境出現(xiàn)問題時(shí)快速響應(yīng)和解決,保障系統(tǒng)的穩(wěn)定運(yùn)行。

以下是一個(gè)完整的定位Java進(jìn)程CPU占用過高問題的腳本

#!/bin/bash

# CPU高占用排查腳本
# 功能:自動(dòng)定位Java進(jìn)程中CPU占用最高的線程并顯示相關(guān)堆棧信息

# 顏色定義
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color

# 打印顏色輸出函數(shù)
print_color() {
    local color=$1
    local message=$2
    echo -e "${color}${message}${NC}"
}

# 檢查必要命令是否存在
check_commands() {
    local commands=("top" "printf" "jstack" "grep" "awk")
    for cmd in "${commands[@]}"; do
        if ! command -v "$cmd" &> /dev/null; then
            print_color "$RED" "錯(cuò)誤: 未找到命令 $cmd,請(qǐng)確保已安裝"
            exit 1
        fi
    done
}

# 顯示使用說明
show_usage() {
    echo "用法: $0 [選項(xiàng)]"
    echo "選項(xiàng):"
    echo "  -h, --help     顯示幫助信息"
    echo "  -l, --lines    指定顯示行數(shù) (默認(rèn): 10)"
    echo "  -p, --process   指定進(jìn)程名 (默認(rèn): java)"
    echo ""
    echo "示例:"
    echo "  $0                    # 使用默認(rèn)設(shè)置"
    echo "  $0 -l 20             # 顯示20行堆棧信息"
    echo "  $0 -p tomcat         # 指定進(jìn)程名為tomcat"
    echo "  $0 -p java -l 15     # 指定進(jìn)程名和顯示行數(shù)"
}

# 解析命令行參數(shù)
PROCESS_NAME="java"
LINES=10

while [[ $# -gt 0 ]]; do
    case $1 in
        -h|--help)
            show_usage
            exit 0
            ;;
        -l|--lines)
            LINES="$2"
            shift 2
            ;;
        -p|--process)
            PROCESS_NAME="$2"
            shift 2
            ;;
        *)
            print_color "$RED" "未知參數(shù): $1"
            show_usage
            exit 1
            ;;
    esac
done

# 主函數(shù)
main() {
    print_color "$BLUE" "================================================"
    print_color "$BLUE" "    Java CPU高占用排查工具"
    print_color "$BLUE" "================================================"
    echo ""
    
    # 檢查必要命令
    check_commands
    
    print_color "$YELLOW" "正在查找進(jìn)程名為 '$PROCESS_NAME' 的進(jìn)程..."
    echo ""
    
    # 獲取CPU占用最高的Java進(jìn)程PID
    local top_pid=$(top -bn1 | grep -i "$PROCESS_NAME" | head -10 | awk 'NR>7 {if($9+0 > 0) print $1,$9}' | sort -k2 -nr | head -1 | awk '{print $1}')
    
    if [[ -z "$top_pid" ]]; then
        print_color "$RED" "未找到進(jìn)程名為 '$PROCESS_NAME' 且CPU占用大于0的進(jìn)程!"
        exit 1
    fi
    
    local cpu_usage=$(top -bn1 -p "$top_pid" | grep "$top_pid" | awk '{print $9}')
    
    print_color "$GREEN" "? 找到目標(biāo)進(jìn)程:"
    echo "  PID: $top_pid"
    echo "  進(jìn)程名: $PROCESS_NAME"
    echo "  CPU使用率: ${cpu_usage}%"
    echo ""
    
    # 獲取進(jìn)程詳細(xì)信息
    print_color "$YELLOW" "獲取進(jìn)程詳細(xì)信息..."
    local process_info=$(ps -p "$top_pid" -o pid,ppid,user,pcpu,pmem,cmd --no-headers)
    echo "  進(jìn)程信息: $process_info"
    echo ""
    
    # 獲取CPU占用最高的線程
    print_color "$YELLOW" "正在分析進(jìn)程 $top_pid 中的線程..."
    local top_thread=$(top -Hbn1 -p "$top_pid" | awk 'NR>7 {if($9+0 > 0) print $1,$9,$12}' | sort -k2 -nr | head -1)
    
    if [[ -z "$top_thread" ]]; then
        print_color "$RED" "未找到CPU占用大于0的線程!"
        exit 1
    fi
    
    local thread_id=$(echo "$top_thread" | awk '{print $1}')
    local thread_cpu=$(echo "$top_thread" | awk '{print $2}')
    local thread_name=$(echo "$top_thread" | awk '{for(i=3;i<=NF;i++) printf $i" "; print ""}' | sed 's/ *$//')
    
    print_color "$GREEN" "? 找到CPU占用最高的線程:"
    echo "  線程ID: $thread_id"
    echo "  線程名: $thread_name"
    echo "  CPU使用率: ${thread_cpu}%"
    echo ""
    
    # 轉(zhuǎn)換線程ID為十六進(jìn)制
    print_color "$YELLOW" "轉(zhuǎn)換線程ID為十六進(jìn)制..."
    local hex_thread_id=$(printf "0x%x" "$thread_id")
    echo "  線程ID(十進(jìn)制): $thread_id"
    echo "  線程ID(十六進(jìn)制): $hex_thread_id"
    echo ""
    
    # 獲取用戶輸入的顯示行數(shù)
    print_color "$YELLOW" "請(qǐng)輸入要顯示的堆棧信息行數(shù) (回車使用默認(rèn)值 $LINES): "
    read -r user_lines
    
    if [[ -n "$user_lines" && "$user_lines" =~ ^[0-9]+$ ]]; then
        LINES="$user_lines"
    fi
    
    echo ""
    print_color "$BLUE" "正在使用 jstack 分析線程堆棧 (顯示 $LINES 行)..."
    print_color "$BLUE" "================================================"
    
    # 使用jstack獲取線程堆棧信息
    local jstack_output
    if jstack_output=$(jstack "$top_pid" 2>/dev/null); then
        echo "$jstack_output" | grep -A "$LINES" "$hex_thread_id"
    else
        print_color "$RED" "執(zhí)行 jstack 失??!可能的原因:"
        echo "  1. 進(jìn)程 $top_pid 不存在"
        echo "  2. 沒有執(zhí)行 jstack 的權(quán)限"
        echo "  3. 進(jìn)程不是Java進(jìn)程"
        echo "  4. JAVA_HOME環(huán)境變量未正確設(shè)置"
        
        # 嘗試使用/proc文件系統(tǒng)獲取信息
        print_color "$YELLOW" "嘗試通過其他方式獲取線程信息..."
        echo "線程狀態(tài):"
        cat "/proc/$top_pid/task/$thread_id/status" | grep -E "^(Name|State|Pid):" 2>/dev/null || echo "無法獲取線程狀態(tài)信息"
    fi
    
    echo ""
    print_color "$BLUE" "================================================"
    print_color "$GREEN" "? 分析完成!"
    echo ""
    print_color "$YELLOW" "建議后續(xù)操作:"
    echo "  1. 查看堆棧信息中的代碼位置"
    echo "  2. 檢查對(duì)應(yīng)的Java源代碼"
    echo "  3. 分析是否存在死循環(huán)、頻繁GC等問題"
    echo "  4. 使用 profiler 工具進(jìn)行深入分析"
}

# 錯(cuò)誤處理
set -e

# 捕捉Ctrl+C
trap 'echo ""; print_color "$RED" "用戶中斷操作"; exit 1' INT

# 運(yùn)行主函數(shù)
main "$@"

保存腳本
將上面的腳本保存為 cpu_debug.sh,并給予執(zhí)行權(quán)限:

chmod +x cpu_debug.sh

運(yùn)行方式
基本用法(默認(rèn)Java進(jìn)程,顯示10行):

./cpu_debug.sh

指定顯示行數(shù):

./cpu_debug.sh -l 20

指定進(jìn)程名:

./cpu_debug.sh -p tomcat

組合使用:

./cpu_debug.sh -p java -l 15

查看幫助:

./cpu_debug.sh -h

流程圖 (Flowchart)
下圖展示了定位CPU占用過高問題的整體步驟與決策邏輯。

flowchart TD
    A[Java應(yīng)用CPU占用飆升] --> B[使用 top 命令<br>定位高CPU進(jìn)程]
    B --> C{找到目標(biāo)Java進(jìn)程?}
    C -- 是 --> D[使用 top -Hp [PID]<br>定位高CPU線程]
    C -- 否 --> A
    D --> E[使用 printf<br>轉(zhuǎn)換線程ID為十六進(jìn)制]
    E --> F[使用 jstack + grep<br>定位問題堆棧]
    F --> G[分析堆棧信息<br>定位問題代碼(如死循環(huán))]
    G --> H[修復(fù)代碼并發(fā)布]

在這里插入圖片描述

序列圖 (Sequence Diagram)

下圖詳細(xì)描述了排查過程中,用戶與各個(gè)系統(tǒng)工具之間的交互時(shí)序。

sequenceDiagram
    participant U as 用戶/運(yùn)維
    participant T as top 命令
    participant P as 問題Java進(jìn)程
    participant S as jstack 命令
    participant G as grep 命令

    Note over U: 開始排查

    U ->> T: 執(zhí)行 top
    T ->> U: 返回進(jìn)程列表<br>(發(fā)現(xiàn)高CPU進(jìn)程PID)
    
    U ->> T: 執(zhí)行 top -Hp [PID]
    T ->> U: 返回線程列表<br>(發(fā)現(xiàn)高CPU線程TID)

    U ->> P: 執(zhí)行 printf “0x%x” [TID]
    P ->> U: 返回十六進(jìn)制線程ID (nid)

    U ->> S: 執(zhí)行 jstack [PID]
    S ->> U: 輸出完整線程堆棧

    U ->> G: 使用 grep 過濾 nid
    G ->> U: 返回問題線程的堆棧<br>(定位到具體代碼行)

    Note over U: 分析代碼并修復(fù)問題

在這里插入圖片描述

以上就是Java應(yīng)用CPU占用過高問題的快速定位和解決方法的詳細(xì)內(nèi)容,更多關(guān)于Java CPU占用過高的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • Java?17新特性從語言增強(qiáng)到運(yùn)行時(shí)優(yōu)化完全解析

    Java?17新特性從語言增強(qiáng)到運(yùn)行時(shí)優(yōu)化完全解析

    Java17是Java編程語言的一個(gè)新版本,它引入了一些新的特性和改進(jìn),使得Java編程更加高效和方便,這篇文章主要介紹了Java 17新特性從語言增強(qiáng)到運(yùn)行時(shí)優(yōu)化的相關(guān)資料,需要的朋友可以參考下
    2026-05-05
  • Java如何比較兩個(gè)對(duì)象并獲取不相等的字段詳解

    Java如何比較兩個(gè)對(duì)象并獲取不相等的字段詳解

    這篇文章主要給大家介紹了關(guān)于Java如何比較兩個(gè)對(duì)象并獲取不相等的字段以及JAVA判斷(獲取)兩個(gè)相同對(duì)象不同的數(shù)據(jù)的相關(guān)資料,文中通過實(shí)例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用java具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2021-11-11
  • Spring?boot?集成?MQTT詳情

    Spring?boot?集成?MQTT詳情

    這篇文章主要介紹了Spring?boot?集成?MQTT詳情,MQTT是一種基于發(fā)布/訂閱模式的"輕量級(jí)"通訊協(xié)議,可以以極少的代碼和有限的帶寬為連接遠(yuǎn)程設(shè)備提供實(shí)時(shí)可靠的消息服,下文更多相關(guān)介紹,需要的小伙伴可以參考一下
    2022-04-04
  • Java集合List快速實(shí)現(xiàn)重復(fù)判斷的10種方案

    Java集合List快速實(shí)現(xiàn)重復(fù)判斷的10種方案

    在Java開發(fā)中,List集合的重復(fù)判斷是高頻操作場景,不當(dāng)?shù)膶?shí)現(xiàn)方式可能導(dǎo)致O(n2)時(shí)間復(fù)雜度,在百萬級(jí)數(shù)據(jù)時(shí)產(chǎn)生分鐘級(jí)延遲,本文通過10種實(shí)現(xiàn)方案對(duì)比,揭示不同場景下的最優(yōu)選擇,需要的朋友可以參考下
    2025-12-12
  • Maven 配置文件 生命周期 常用命令詳解

    Maven 配置文件 生命周期 常用命令詳解

    Maven是圍繞著構(gòu)建生命周期的核心概念為原型,整個(gè)項(xiàng)目的創(chuàng)建和部署都是圍繞著生命周期展開的,一個(gè)生命周期由若干個(gè)生命周期階段組成。下面通過本文給大家介紹Maven 配置文件 生命周期 常用命令詳解,一起看看吧
    2017-11-11
  • BlockingQueue隊(duì)列處理高并發(fā)下的日志

    BlockingQueue隊(duì)列處理高并發(fā)下的日志

    這篇文章主要介紹了BlockingQueue隊(duì)列處理高并發(fā)下的日志示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步
    2022-03-03
  • 你一定不知道的Java Unsafe用法詳解

    你一定不知道的Java Unsafe用法詳解

    Unsafe是位于sun.misc包下的一個(gè)類,主要提供一些用于執(zhí)行低級(jí)別、不安全操作的方法,如直接訪問系統(tǒng)內(nèi)存資源、自主管理內(nèi)存資源等,下面這篇文章主要給大家介紹了關(guān)于Java Unsafe用法的相關(guān)資料,需要的朋友可以參考下
    2021-10-10
  • SpringBoot解決jar包沖突的問題,簡單有效

    SpringBoot解決jar包沖突的問題,簡單有效

    這篇文章主要介紹了SpringBoot解決jar包沖突的問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-09-09
  • Java通過底層原碼了解數(shù)組拷貝

    Java通過底層原碼了解數(shù)組拷貝

    一般說起數(shù)組的拷貝,首先想到的就是用循環(huán)對(duì)數(shù)組進(jìn)行拷貝。但其實(shí)JAVA為我們提供了一些拷貝數(shù)組比較方便的方法,有完全拷貝的方法,也有部分拷貝的方法。接下來就一一介紹這些方法
    2022-07-07
  • SpringBoot使用SOFA-Lookout監(jiān)控的方法

    SpringBoot使用SOFA-Lookout監(jiān)控的方法

    本文介紹SpringBoot使用螞蟻金服SOFA-Lookout配合Prometheus進(jìn)行監(jiān)控,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2019-03-03

最新評(píng)論

新兴县| 长垣县| 云南省| 福泉市| 北票市| 启东市| 黄山市| 广东省| 龙川县| 隆回县| 平原县| 镇江市| 正镶白旗| 青阳县| 登封市| 西充县| 濮阳县| 砀山县| 剑川县| 崇阳县| 岑溪市| 洪泽县| 莫力| 伊金霍洛旗| 大兴区| 遵化市| 盐边县| 永嘉县| 浦东新区| 花莲市| 中卫市| 兴安县| 历史| 岑巩县| 杨浦区| 金昌市| 大姚县| 绥中县| 夏邑县| 渭南市| 黎川县|