今日分享:windows 如何查看 JAVA 进程详情脚本
使用方式:
使用方式方法就是在桌面创建一个test文本文件,然后将后缀改为.bat,开启一个命令提示符,然后使用jps -lv命令来搜索java进程找到你想要查询的JAVA进程PID然后再工具页面输入等待日志文件的生成即可
输入一个 Java 进程 PID → 自动生成热点线程列表 → 自动抓 jstack → 自动提取热点线程栈 → 帮你快速排查 CPU 高、卡死、死循环、阻塞等问题。
功能和专业工具类似(如 Arthas、Async-Profiling 的简化版)
使用后会生成一个文件夹,文件夹名称叫做JavaHot,其中有四个文件
- topthreads_22252.txt:热点线程列表(CPU 最高的前 10 个线程)
用于找:哪个线程最耗 CPU,哪个线程需要重点分析。
- jstack_22252.txt:完整的 Java 线程栈(jstack 原始输出)
包含所有 Java 线程的完整堆栈,是基础数据,但通常不需要人工查看。
- hotstacks_22252.txt:热点线程的栈分析报告(最终关键文件)
脚本自动从 jstack 中提取前 10 个热线程的栈,是你排查问题最主要看的文件。
- jstack_err_22252.txt:抓取 jstack 过程中的错误信息
正常情况下为空,如果 jstack 抓取失败,这里会记录错误原因。
比较重要的是,topthreads与hotstacks
废话不多说了上代码
@echo off
setlocal EnableExtensions EnableDelayedExpansion
echo ================================================
set /p PID=請輸入 Java 進程 PID:
if "%PID%"=="" ( echo [ERR] 未輸入 PID & exit /b 1 )
rem 準備輸出目錄
set "OUTDIR=%USERPROFILE%\Desktop\JavaHot"
if not exist "%OUTDIR%" mkdir "%OUTDIR%"
rem 校驗 PID 是否存在
for /f "tokens=2 delims=," %%A in ('wmic process where "ProcessId=%PID%" get ProcessId^,Name /format:csv ^| find "%PID%"') do set "FOUND=%%A"
if "%FOUND%"=="" (
echo [ERR] 找不到 PID=%PID% 的進程。請用 "jps -v" 或 "tasklist" 確認。
exit /b 2
)
rem 嘗試定位 jstack/jcmd
set "JSTACK=%JAVA_HOME%\bin\jstack.exe"
set "JCMD=%JAVA_HOME%\bin\jcmd.exe"
where jstack >nul 2>&1 && for %%F in (jstack.exe) do set "JSTACK=%%~$PATH:F"
where jcmd >nul 2>&1 && for %%F in (jcmd.exe) do set "JCMD=%%~$PATH:F"
echo [INFO] 輸出目錄: "%OUTDIR%"
echo [INFO] jstack: "%JSTACK%"
echo [INFO] jcmd : "%JCMD%"
rem 1) 生成前10個熱線程清單
echo [STEP] 生成熱線程清單...
powershell -NoProfile -ExecutionPolicy Bypass ^
-Command "$p=Get-Process -Id %PID%; $p.Threads | Sort-Object TotalProcessorTime -Descending | Select -First 10 Id,TotalProcessorTime | %%{ '{0,8} 0x{1:X} {2}' -f $_.Id,$_.Id,$_.TotalProcessorTime } | Out-File -Encoding UTF8 '%OUTDIR%\topthreads_%PID%.txt'" || (
echo [ERR] 生成熱線程清單失敗(PID 或權限問題)。 & exit /b 3
)
if not exist "%OUTDIR%\topthreads_%PID%.txt" ( echo [ERR] 未生成熱線程清單文件。 & exit /b 31 )
rem 2) 抓取 jstack(失敗則回退 jcmd Thread.print)
echo [STEP] 抓取线程棧...
set "DUMP=%OUTDIR%\jstack_%PID%.txt"
if exist "%DUMP%" del /q "%DUMP%"
if exist "%JSTACK%" (
"%JSTACK%" -l %PID% > "%DUMP%" 2> "%OUTDIR%\jstack_err_%PID%.txt"
)
for %%A in ("%DUMP%") do set SIZE=%%~zA
if not defined SIZE if exist "%JCMD%" (
echo [INFO] jstack 失敗,回退 jcmd Thread.print
"%JCMD%" %PID% "Thread.print" > "%DUMP%" 2>> "%OUTDIR%\jstack_err_%PID%.txt"
)
set "SIZE="
for %%A in ("%DUMP%") do set SIZE=%%~zA
if not defined SIZE (
echo [ERR] 無法抓取线程棧。常見原因:未安裝 JDK/未在 PATH、位寬不匹配(32/64位)、權限不足。
if exist "%OUTDIR%\jstack_err_%PID%.txt" echo -------------- 錯誤輸出 -------------- & type "%OUTDIR%\jstack_err_%PID%.txt"
exit /b 4
)
rem 3) 從 jstack 中抽取前10熱線程的棧
echo [STEP] 解析熱線程棧...
powershell -NoProfile -ExecutionPolicy Bypass ^
-Command "$top = Get-Content '%OUTDIR%\topthreads_%PID%.txt'; $dump='%DUMP%'; $out='%OUTDIR%\hotstacks_%PID%.txt'; $rep=@('=== Java PID %PID% 熱線程清單 ==='); $rep += $top; $rep+=''; $rep+='=== 线程栈(按上表順序) ==='; foreach($line in $top){ if($line -match '0x([0-9A-F]+)'){ $hex=$Matches[1]; $rep+=''; $rep+=('----- nid=0x{0} -----' -f $hex); $m = Select-String -Path $dump -Pattern ('nid=0x{0}' -f $hex) -Context 0,60; if($m){ $rep += $m.Line; $rep += $m.Context.PostContext } else { $rep += ('未在 dump 中找到 nid=0x{0}' -f $hex) } } } ; Set-Content -Encoding UTF8 -Path $out -Value $rep" || (
echo [ERR] 解析熱線程棧失敗。 & exit /b 5
)
echo.
echo 完成
echo 熱线程清單: "%OUTDIR%\topthreads_%PID%.txt"
echo 线程栈報告: "%OUTDIR%\hotstacks_%PID%.txt"
echo 原始 jstack : "%OUTDIR%\jstack_%PID%.txt"
exit /b 0
看不懂,但是膜拜大佬~