Intro
執行
java -jar xxx.jar
時,出現了 java 進程卡住,屏幕上沒有任何輸出。
Debug 過程
查看系統日誌
查看 /var/log/syslog、/var/log/messages,都沒有報錯信息。
查看 Java 進程自己的輸出日誌
沒有報錯。
查看系統級別信息
# 查看進程
ps -ef |grep java
# 查看系統負載,沒有消耗過多資源
top
# 查看內存使用情況
free -mh
# 查看端口占據,沒有出現端口被佔的情況
ss -anp |grep 9600
查看 Java pid 對應的 /proc/[pid]/ 目錄內容
以下參考鏈接:Java程序卡住問題的解決
/proc/pid/cmdline 進程啓動命令
/proc/pid/cwd 鏈接到進程當前工作目錄
/proc/pid/environ 進程環境變量列表
/proc/pid/exe 鏈接到進程的執行命令文件
/proc/pid/fd 包含進程相關的所有的文件描述符
/proc/pid/maps 與進程相關的內存映射信息
/proc/pid/mem 指代進程持有的內存,不可讀
/proc/pid/root 鏈接到進程的根目錄
/proc/pid/stat 進程的狀態
/proc/pid/statm 進程使用的內存的狀態
/proc/pid/status 進程狀態信息,比stat/statm更具可讀性
/proc/self 鏈接到當前正在運行的進程
查看 /proc/[pid]/status,沒有異常
Name: java
Umask: 0002
State: S (sleeping)
Tgid: 6545
Ngid: 0
Pid: 6545
PPid: 1
TracerPid: 0
Uid: 1001 1001 1001 1001
Gid: 1001 1001 1001 1001
FDSize: 256
Groups: 27 1001
NStgid: 6545
NSpid: 6545
NSpgid: 6545
NSsid: 30676
VmPeak: 5710304 kB
VmSize: 5710304 kB
VmLck: 0 kB
VmPin: 0 kB
VmHWM: 1026260 kB
VmRSS: 1020728 kB
RssAnon: 1002968 kB
RssFile: 17760 kB
RssShmem: 0 kB
VmData: 1364668 kB
VmStk: 132 kB
VmExe: 4 kB
VmLib: 17620 kB
VmPTE: 2488 kB
VmSwap: 0 kB
HugetlbPages: 0 kB
CoreDumping: 0
Threads: 45
SigQ: 0/31804
SigPnd: 0000000000000000
ShdPnd: 0000000000000000
SigBlk: 0000000000000000
SigIgn: 0000000000000000
SigCgt: 2000000181005ccf
CapInh: 0000000000000000
CapPrm: 0000000000000000
CapEff: 0000000000000000
CapBnd: 0000003fffffffff
CapAmb: 0000000000000000
NoNewPrivs: 0
Seccomp: 0
Speculation_Store_Bypass: thread vulnerable
Cpus_allowed: f
Cpus_allowed_list: 0-3
Mems_allowed: 00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000001
Mems_allowed_list: 0
voluntary_ctxt_switches: 1
nonvoluntary_ctxt_switches: 0
查看 /proc/[pid]/cwd/,鏈接了執行目錄,看不出特別的。
查看 /proc/[pid]/task/,鏈接了子進程,看不出異常。
jvm 堆棧信息查看
# 查看 java 進程
jps
# 查看堆內存,用於定位死鎖
jstack -l [pid]
也可以使用這個方法查看,參考鏈接:Java程序卡住問題的解決
kill -3 [pid]
kill命令只能在linux下面用,其實也可以用jdk自帶的工具,比如用jstack去查看線程運行情況,這樣在windows下面也可以使用。總結:Java是一個很開放的程序,對於出問題的情況利用提供的工具大部分都很容易定位。這中間一是你要知道有什麼樣的工具可以輔助你,至少你要把jdk/bin下面自帶的工具看一遍;另外就是要有藉助工具解決問題的意識,如果還是和剛開始學寫代碼的時候就知道到處打印輸出的語句,那解決問題的層次實在是太低了,也很難把問題真正解決。
Java Thread State
以下參考鏈接: 各種 Java Thread State 第一分析法則
4,如果大量線程在“waiting on condition”:
可能是它們又跑去獲取第三方資源,尤其是第三方網絡資源,遲遲獲取不到Response,導致大量線程進入等待狀態。
所以如果你發現有大量的線程都處在 Wait on condition,從線程堆棧看,正等待網絡讀寫,這可能是一個網絡瓶頸的徵兆,因爲網絡阻塞導致線程無法執行。
Summary
最終在 jstack 中定位到了卡住的位置,是網卡多 ip 綁定導致的,作相應調整即可。另,引言中定位 Java 的思路值得借鑑。
"spring.cloud.inetutils" #12 daemon prio=5 os_prio=0 tid=0x00007f99a466a000 nid=0x482b waiting on condition [0x00007f998756d000]
java.lang.Thread.State: WAITING (parking)
at sun.misc.Unsafe.park(Native Method)
- parking to wait for <0x0000000083e37c70> (a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject)
at java.util.concurrent.locks.LockSupport.park(LockSupport.java:175)
at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:2039)
at java.util.concurrent.LinkedBlockingQueue.take(LinkedBlockingQueue.java:442)
at java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:1074)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1134)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:748)
Reference
- 一次完整 debug 的博客參考: 記一次找因redis使用不當導致應用卡死bug的過程