快速定位Java服務線上“系統性”故障

參考自 http://techblog.youdao.com/?p=961

在分析具體故障,先介紹一下幾種常用的工具

JDK中帶有了一堆的工具是可以用來查看運行狀況,排查問題的,但對于這些工具還是要比較清楚執行后會發生什么,否則有可能會因為執行了一個命令就導致嚴重故障,首先重點講下影響比較大的jmap。

最主要的危險操作是下面這三種:
1.jmap -dump
jmap -dump:format=b,file=heap.hprof 1234。
這個命令執行,JVM會將整個heap的信息dump寫入到一個文件,heap如果比較大的話,就會導致這個過程比較耗時,并且執行的過程中為了保證dump的信息是可靠的,所以會暫停應用。
可以通過-d64來解決(jmap -J-d64 -dump:format=b,file=dump.bin PID)
而jdk7的某個版本則會拋出異常,這是jdk的bug.
一般dump下來的內存有幾個G,而有時候dump下來只有一兩百兆,說明jmap有問題,需要多執行幾次jmap -dump才能得出正常結果,這個時候可以選用
gcore 把整個內存dump出來,然后再使用jmap把core dump轉換成heap dump。
做法就是用gcore 1234命令來生成c版的core文件,再用命令jmap -dump:format=b,file=heap.hprof /bin/java core.1234.

2.jmap -permstat
這個命令執行,JVM會去統計perm區的狀況,這整個過程也會比較的耗時,并且同樣也會暫停應用。

**3. jmap -histo:live **
這個命令執行,JVM會先觸發gc,然后再統計信息。

jmap導出的文件怎么進行分析呢,這時候就會用到一些分析工具,我比較常用的是 IBM HeapAnalyzer工具,具體的用法大家自己查一下,啟動方法如下
java -jar -Xmx3000m ha455.jar


另外一個比較常用工具是jstat,jstat是JDK自帶的一個輕量級小工具。全稱“Java Virtual Machine statistics monitoring tool”,它位于Java的bin目錄下,主要利用JVM內建的指令對Java應用程序的資源和性能進行實時的命令行的監控,包括了對Heap size和垃圾回收狀況的監控??梢?,Jstat是輕量級的、專門針對JVM的工具,非常適用。
jstat工具特別強大,有眾多的可選項,詳細查看堆內各個部分的使用量,以及加載類的數量。使用時,需加上查看進程的進程id,和所選參數。我比較常用的是如下命令1234 代表進程號,1000,10 代表每1秒輸入一次JVM資源使用情況,共輸出10次。
**jstat -gcutil 1234 1000 10 **


另外排查OOM通常要結合tomcat的日志、gc日志來查看。如果沒有任何JVM參數設置,gc日志默認打印在stdout.log文件里,里面可能會打其他的日志,而且GC日志也不會輸出時間,所以在JVM啟動參數里最好加以下命令,規范下GC日志輸出到/home/admin/logs/gc.log,并且打印GC時間。
-XX:+HeapDumpOnOutOfMemoryError
-XX:HeapDumpPath=/home/admin/logs
-Xloggc:/home/admin/logs/gc.log
-XX:+PrintGCDetails
-XX:+PrintGCDateStamps


下面進入正題

一、摘要

由于硬件問題、系統資源緊缺或者程序本身的BUG,Java服務在線上不可避免地會出現一些“系統性”故障,比如:服務性能明顯下降、部分(或所有)接口超時或卡死等。其中部分故障隱藏頗深,對運維和開發造成長期困擾。筆者根據自己的學習和實踐,總結出一套行之有效的“逐步排除”的方法,來快速定位Java服務線上“系統性”故障。

二、導言

Java語言是廣泛使用的語言,它具有跨平臺的特性和易學易用的特點,很多服務端應用都采用Java語言開發。由于軟件系統本身以及運行環境的復雜性,Java的應用不可避免地會出現一些故障。盡管故障的表象通常比較明顯(服務反應明顯變慢、輸出發生錯誤、發生崩潰等),但故障定位卻并不一定容易。為什么呢?有如下原因:

  1. 程序打印的日志越詳細,越容易定位到BUG,但是可能有些時候程序中沒有打印相關內容到日志,或者日志級別沒有設置到相應級別

  2. 程序可能只對很特殊的輸入條件發生故障,但輸入條件難以推斷和復現

  3. 通常自己編寫的程序出現的問題會比較容易定位,但應用經常是由多人協作編寫,故障定位人員可能并不熟悉其他人員編寫的程序

  4. 應用通常會依賴很多第三方庫,第三方庫中隱藏著的BUG可能是始料未及的

  5. 多數的開發人員學習的都是“如何編寫業務功能”的技術資料,但對于“如何編寫高效、可靠的程序”、“如何定位程序故障”卻知之甚少。所以一旦應用出現故障,他們并沒有足夠的技術背景知識來幫助他們完成故障定位。

盡管有些故障會很難定位,但筆者根據學習和實踐總結出一套“逐步排除”的故障定位方法:通過操作系統和Java虛擬機提供的監控和診斷工具,獲取到系統資源和目標服務(出現故障的Java服務)內部的狀態,并依據服務程序的特點,識別出哪些現象是正常的,哪些現象是異常的。而后通過排除正常的現象,和跟蹤異?,F象,就可以達到****故障定位的目標。

在正式介紹該方法之前,先申明一下這個方法使用的范圍。

三、本方法適用的范圍

本方法主要適用于Linux系統中Java服務線上“系統性”故障的定位,比如:服務性能明顯下降、部分(或所有)接口超時或卡死。其它操作系統或其它語言的服務,也可以參考本文的思路。

不適用本方法的情況:對于“功能性”故障,例如運算結果不對、邏輯分支走錯等,不建議使用本方法。對待這些情況比較恰當的方法是在測試環境中重現,并使用Java虛擬機提供的“遠程調試”功能進行動態跟蹤調試。

前面說過,本方法基于“異?,F象”的識別來定位故障。那系統中可能有哪些異常現象呢?

四、有哪些異常現象

我們可以將異?,F象分成兩類:系統資源的異?,F象、“目標服務”內部的異?,F象。目標服務,指的是出現故障的Java服務。

  1. 系統資源的異?,F象
    一個程序由于BUG或者配置不當,可能會占用過多的系統資源,導致系統資源匱乏。這時,系統中其它程序就會出現計算緩慢、超時、操作失敗等“系統性”故障。常見的系統資源異?,F象有:CPU占用過高、物理內存富余量極少、磁盤I/O占用過高、發生換入換出過多、網絡鏈接數過多??梢酝ㄟ^top、iostat、vmstat、netstat工具獲取到相應情況。

  2. 目標服務內部的異?,F象
    Java堆滿Java堆是“Java虛擬機”從操作系統申請到的一大塊內存,用于存放Java程序運行中創建的對象。當Java堆滿或者較滿的情況下,會觸發“Java虛擬機”的“垃圾收集”操作,將所有“不可達對象”(即程序邏輯不能引用到的對象)清理掉。有時,由于程序邏輯或者Java堆參數設置的問題,會導致“可達對象”(即程序邏輯可以引用到的對象)占滿了Java堆。這時,Java虛擬機就會無休止地做“垃圾回收”操作,使得整個Java程序會進入卡死狀態。我們可以使用jstat工具查看Java堆的占用率。
    日志中的異常目標服務可能會在日志中記錄一些異常信息,例如超時、操作失敗等信息,其中可能含有系統故障的關鍵信息。
    疑難雜癥死鎖、死循環、數據結構異常(過大或者被破壞)、集中等待外部服務回應等現象。這些異常現象通常采用jstack工具可以獲取到非常有用的線索。

了解異常現象分類之后,我們來具體講講故障定位的步驟。

五、故障定位的步驟

我們采用“從外到內,逐步排除”的方式來定位故障:

  1. 先排除其它程序過度占用系統資源的問題
  2. 然后排除“目標服務”本身占用系統資源過度的問題
  3. 最后觀察目標服務內部的情況,排除掉各種常見故障類型。
    對于不能排除的方面,要根據該信息對應的“危險程度”來判斷是應該“進一步深入”還是“暫時跳過”。例如“目標服務Java堆占用100%”這是一條危險程度較高的信息,建議立即“進一步深入”。而對于“在CPU核數為8的機器上,其它程序偶然占用CPU達200%”這種危險程度不是很高的信息,則建議“暫時跳過”。當然,有些具體情況還需要故障排查人員根據自己的經驗做出判斷。

第一步:排除其它程序占用過量系統資源的情況


圖示:排除其它程序占用過量系統資源的情況

  1. 運行【top】,檢查CPU idle情況,如果發現idle較多(例如多余50%),則排除其它進程占用CPU過量的情況。

    如果idle較少,則按shift+p,將進程按照CPU占用率從高到低排序,逐一排查(見下面TIP)。

  2. 運行【free -g】,檢查剩余物理內存(“-/+ buffer/cache”行的“free”列)情況,如果發現剩余物理內存較多(例如剩余2GB以上),則排除占用物理內存過量的情況。


    如果剩余物理內存較少(例如剩余1GB以下),則運行【vmstat -n 1】檢查si/so(換入換出)情況,
    vmstat

    第一行數值表示的是從系統啟動到運行命令時的均值,我們忽略掉。從第二行開始,每一行的si/so表示該秒內si/so的block數。如果多行數值都為零,則可以排除物理內存不足的問題。如果數值較大(例如大于1000 blocks/sec,block的大小一般是1KB)則說明存在較明顯的內存不足問題。我們可以運行【top】輸入shift+m,將進程按照物理內存占用(“RES”列)從大到小進行排序,然后對排前面的進程逐一排查(見下面TIP)。

  3. 如果目標服務是磁盤I/O較重的程序,則用【iostat -d 1】,檢查磁盤I/O情況。若“目標服務對應的磁盤”讀寫量在預估之內(預估要注意cache機制的影響),則排除其它進程占用磁盤I/O過量的問題。


    第一組數據是從該機器從開機以來的統計值。從第二組開始,都是每秒鐘的統計值。通過【df】命令,可以看到Device與目錄的關系。下圖設備“sdb”就對應了目錄“/disk2”。
    df

假如發現目標服務所在磁盤讀寫量明顯超過推算值,則應該找到大量讀寫磁盤的進程(見下面TIP)

4.運行【netstat -aonp | grep tcp| wc -l】查看各種狀態的TCP連接數量和。如果總數較?。ɡ缧∮?00),則排除連接數占用過多問題。
假如發現連接數較多,可以用【netstat -natp|awk ‘{print $7}’|sort|uniq -c|sort -rn】按照PID統計TCP連接的數量,然后對連接數較多的進程逐一排查(見下面TIP)。

TIP:如何“逐一排查”:假如定位到是某個外部程序占用過量系統資源,則依據進程的功能和配置情況判斷是否合乎預期。假如符合預期,則考慮將服務遷移到其他機器、修改程序運行的磁盤、修改程序配置等方式解決。假如不符合預期,則可能是運行者對該程序不太了解或者是該程序發生了BUG。外部程序通常可能是Java程序也可能不是Java程序,如果是Java程序,可以把它當作目標服務一樣進行排查;而非Java程序具體排查方法超出了本文范圍,列出三個工具供參考選用:
系統提供的調用棧的轉儲工具【pstack】,可以了解到程序中各個線程當前正在干什么,從而了解到什么邏輯占用了CPU、什么邏輯占用了磁盤等
系統提供的調用跟蹤工具【strace】,可以偵測到程序中每個系統API調用的參數、返回值、調用時間等。從而確認程序與系統API交互是否正常等。
系統提供的調試器【gdb】,可以設置條件斷點偵測某個系統函數調用的時候調用棧是什么樣的。從而了解到什么邏輯不斷在分配內存、什么邏輯不斷在創建新連接等

TIP:如何“找到大量讀寫磁盤的進程”:

  1. 如果Linux系統比較新(kernel v2.6.20以上)可以使用iotop工具獲知每個進程的io情況,較快地定位到讀寫磁盤較多的進程。
  2. 通過【ls -l /proc/*/fd | grep 該設備映射裝載到的文件系統路徑】查看到哪個進程打開了該設備的文件,并根據進程身份、打開的文件名、文件大小等屬性判斷是否做了大量讀寫。
  3. 可以使用pstack取得進程的線程調用棧,或者strace跟蹤磁盤讀寫API來幫助確認某個進程是否在做磁盤做大量讀寫

第二步:排除目標服務占用了過量系統資源的情況


圖示:排除目標服務占用了過量系統資源的情況
1.** 運行【top】,shift+p按照“CPU使用”從高到低的排序查看進程,假如目標服務占用的CPU較低(<100%,即小于一個核的計算量),或者符合經驗預期,則排除目標服務CPU占用過高的問題。**
假如目標服務占用的CPU較高(>100%,即大于一個核的計算量),則shift+h觀察線程級別的CPU使用分布。
如果CPU使用分散到多個線程,而且每個線程占用都不算高(例如都<30%),則排除CPU占用過高的問題
如果CPU使用集中到一個或幾個線程,而且很高(例如都>95%),則用【jstack pid > jstack.log】獲取目標服務中線程調用棧的情況。top中看到的占用CPU較高的線程的PID轉換成16進制(字母用小寫),然后在jstack.log中找到對應線程,檢查其邏輯:假如對應線程是純計算型任務(例如GC、正則匹配、數值計算等),則排除CPU占用過高的問題。當然如果這種線程占用CPU總量如果過多(例如占滿了所有核),則需要對線程數量做控制(限制線程數 < CPU核數)。
假如對應線程不是純計算型任務(例如只是向其他服務請求一些數據,然后簡單組合一下返回給用戶等),而該線程CPU占用過高(>95%),則可能發生了異常。例如:死循環、數據結構過大等問題,確定具體原因的方法見下文“第三步:目標進程內部觀察”。

2.** 運行【top】,shift+m按照“物理內存使用(RES)”從高到低排序進程,評估目標服務占的內存量是否在預期之內。如果在預期之內,則排除目標服務Native內存占用過高的問題。**
提示:由于Java進程中有Java級別的內存占用,也有Native級別的內存占用,所以Java進程的“物理內存使用(RES)”比“-Xmx參數指定的Java堆大小”大一些是正常的(例如1.5~2倍左右)。
假如“物理內存使用(RES)”超出預期較多(例如2倍以上),并且確定JNI邏輯不應該占用這么多內存,則可能是NIO或JNI代碼出現了BUG。由于本文主要討論的是Java級別的問題,所以對這種情況不做過多討論。讀者可以參考上文“TIP:如何逐一排查”進行native級別的調試。

第三步:目標服務內部觀察


圖示:目標服務內部觀察
1. Java堆占用情況
** 用【jstat -gcutil pid】查看目標服務的OLD區占用比例,假如占用比例低于85%則排除Java堆占用比例過高的問題。**
假如占用比例較高(例如超過98%),則服務存在Java堆占滿的問題。這時候可以用jmap+mat進行分析定位內存中占用比例的情況(見下文TIP),從而較快地定位到Java堆滿的原因。

TIP:用jmap+mat進行分析定位內存中占用比例的情況
先通過【jmap -dump:file=dump.map pid】取得目標服務的Java堆轉儲,然后找一臺空閑內存較大的機器在VNC中運行mat工具。mat工具中打開dump.map后,可以方便地分析內存中什么對象引用了大量的對象(從邏輯意義上來說,就是該對象占用了多大比例的內存)。具體使用可以ca

2. 異常日志觀察
通過類似【tail -10000 stdout.log.2014-08-15 | grep -B2 -A10 -i exception】這樣的方式,可以查到日志中最近記錄的異常。

3. 疑難雜癥
用【jstack pid > jstack.log】獲取目標服務中“鎖情況”和“各線程調用棧”信息,并分析
檢查jstack.log中是否有deadlock報出,如果沒有則排除deadlock情況。

*Found one Java-level deadlock:*

*=============================*

*“Thread-0″:*

*  waiting to lock monitor 0x1884337c (object 0x046ac698, a java.lang.Object),*

*  which is held by “main”*

*“main”:*

*  waiting to lock monitor 0x188426e4 (object 0x046ac6a0, a java.lang.Object),*

*  which is held by “Thread-0″*

* *
*Java stack information for the threads listed above:*
*===================================================*
*“Thread-0″:*
* at LockProblem$T2.run(LockProblem.java:14)*
* - waiting to lock <0x046ac698> (a java.lang.Object)*
* - locked <0x046ac6a0> (a java.lang.Object)*
*“main”:*
* at LockProblem.main(LockProblem.java:25)*
* - waiting to lock <0x046ac6a0> (a java.lang.Object)*
* - locked <0x046ac698> (a java.lang.Object)*
* *
*Found 1 deadlock.*

如果發現deadlock則則根據jstack.log中的提示定位到對應代碼邏輯。
用【POST http://www.xinitek.com/ajax/summaryJStack < jstack.log > jstack.log.summary】對jstack.log做合并處理,然后繼續分析故障所在。

通過jstack.log.summary中的情況,我們可以較迅速地定位到一些嫌疑點,并可以猜測其故障引起的原因(后文有jstack.log.summary情況舉例供參考)

Paste_Image.png

猜測了原因后,可以通過日志檢查、監控檢查、用測試程序嘗試復現等方式確認猜測是否正確。如果需要更細致的證據來確認,可以通過BTrace、strace、jmap+MAT等工具進行分析,最終確認問題所在。

下面簡單介紹下這幾個工具:
BTrace:用于監測Java級別的方法調用情況。可以對運行中的Java虛擬機插入調試代碼,從而確認方法每次調用的參數、返回值、花費時間等。第三方免費工具。
strace:用于監視系統調用情況。可以得到每次系統調用的參數、返回值、耗費時間等。Linux自帶工具。
jmap+MAT:用于查看Java級別內存情況。jmap是JDK自帶工具,可以將Java程序的Java堆轉儲到數據文件中;MAT是eclipse.org上提供的一個工具,可以檢查jmap轉儲數據文件中的數據。結合這兩個工具,我們可以非常容易地看到Java程序內存中所有對象及其屬性。

TIP:jstack.log.summary情況舉例
1.某種線程數量過多

*1000 threads at*
*“Timer-0″ prio=6 tid=0x189e3800 nid=0x34e0 in Object.wait() [0x18c2f000]*
*   java.lang.Thread.State: TIMED_WAITING (on object monitor)*
* at java.lang.Object.wait(Native Method)*
* at java.util.TimerThread.mainLoop(Timer.java:552)*
* - locked [***] (a java.util.TaskQueue)*
* at java.util.TimerThread.run(Timer.java:505)*

2.多個線程在等待一把鎖,但拿到鎖的線程在做數據結構遍歷操作

*38 threads at*
*“Thread-44″ prio=6 tid=0×18981800 nid=0x3a08 waiting for monitor entry [0x1a85f000]*
*   java.lang.Thread.State: BLOCKED (on object monitor)*
* at SlowAction$Users.run(SlowAction.java:15)*
* - waiting to lock [***] (a java.lang.Object)*

* *
*1 threads at*
*“Thread-3″ prio=6 tid=0x1894f400 nid=0×3954 runnable [0x18d1f000]*
*   java.lang.Thread.State: RUNNABLE*
* at java.util.LinkedList.indexOf(LinkedList.java:603)*
* at java.util.LinkedList.contains(LinkedList.java:315)*
* at SlowAction$Users.run(SlowAction.java:18)*
* - locked [***] (a java.lang.Object)*

3.某個應當被緩存的對象多次被創建(數據庫連接)

99 threads at
“resin-tcp-connection-*:3231-321″ daemon prio=10 tid=0x000000004dc43800 nid=0x65f5 waiting for monitor entry [0x00000000507ff000]
    java.lang.Thread.State: BLOCKED (on object monitor)
         at org.apache.commons.dbcp.PoolableConnectionFactory.makeObject(PoolableConnectionFactory.java:290)
         - waiting to lock <0x00000000b26ee8a8> (a org.apache.commons.dbcp.PoolableConnectionFactory)
         at org.apache.commons.pool.impl.GenericObjectPool.borrowObject(GenericObjectPool.java:771)
         at org.apache.commons.dbcp.PoolingDataSource.getConnection(PoolingDataSource.java:95)
* *
1 threads 
at “resin-tcp-connection-*:3231-149″ daemon prio=10 tid=0x000000004d67e800 nid=0x66d7 runnable [0x000000005180f000]
 java.lang.Thread.State: RUNNABLE
  …
at org.apache.commons.dbcp.DriverManagerConnectionFactory.createConnection(DriverManagerConnectionFactory.java:46)
at org.apache.commons.dbcp.PoolableConnectionFactory.makeObject(PoolableConnectionFactory.java:290)
 - locked <0x00000000b26ee8a8> (a org.apache.commons.dbcp.PoolableConnectionFactory)
at org.apache.commons.pool.impl.GenericObjectPool.borrowObject(GenericObjectPool.java:771)
at org.apache.commons.dbcp.PoolingDataSource.getConnection(PoolingDataSource.java:95)
at …

4.很多線程都在等待外部服務的響應

100 threads at
“Thread-0″ prio=6 tid=0x189cdc00 nid=0×2904 runnable [0x18d5f000]
java.lang.Thread.State: RUNNABLE
atjava.net.SocketInputStream.socketRead0(Native Method)
at java.net.SocketInputStream.read(SocketInputStream.java:150)
at java.net.SocketInputStream.read(SocketInputStream.java:121)…
at RequestingService$RPCThread.run(RequestingService.java:24)

5.很多線程都在等待FutureTask完成,而FutureTask在等待外部服務的響應

100 threads at
“Thread-0″ prio=6 tid=0×18861000 nid=0x38b0 waiting on condition [0x1951f000]
   java.lang.Thread.State: WAITING (parking)
 at sun.misc.Unsafe.park(Native Method)
 - parking to wait for [***] (a java.util.concurrent.FutureTask$Sync)
 at java.util.concurrent.locks.LockSupport.park(LockSupport.java:186)
 at java.util.concurrent.locks.AbstractQueuedSynchronizer.parkAndCheckInterrupt(AbstractQueuedSynchronizer.java:834)
 at java.util.concurrent.locks.AbstractQueuedSynchronizer.doAcquireSharedInterruptibly(AbstractQueuedSynchronizer.java:994)
 at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireSharedInterruptibly(AbstractQueuedSynchronizer.java:1303)
 at java.util.concurrent.FutureTask$Sync.innerGet(FutureTask.java:248)
 at java.util.concurrent.FutureTask.get(FutureTask.java:111)
 at IndirectWait$MyThread.run(IndirectWait.java:51)
 
100 threads at
“pool-1-thread-1″ prio=6 tid=0x188fc000 nid=0×2834 runnable [0x1d71f000]
java.lang.Thread.State: RUNNABLEat java.net.SocketInputStream.socketRead0(Native Method)
at java.net.SocketInputStream.read(SocketInputStream.java:150)
at java.net.SocketInputStream.read(SocketInputStream.java:121)…
at IndirectWait.request(IndirectWait.java:23)
at IndirectWait$MyThread$1.call(IndirectWait.java:46)
at IndirectWait$MyThread$1.call(IndirectWait.java:1)
at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:334)
at java.util.concurrent.FutureTask.run(FutureTask.java:166)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1110)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:603)
at java.lang.Thread.run(Thread.java:722)

為方便讀者使用,將故障定位三個步驟的圖合并如下:

all

圖示:故障定位步驟匯總

故障定位是一個較復雜和需要經驗的過程,如果現在故障正在發生,對于分析經驗不很多的開發或運維人員,有什么簡單的操作步驟記錄下需要的信息嗎?下面提供一個

六、給運維人員的簡單步驟

如果事發突然且不能留著現場太久,要求運維人員:

  1. top: 記錄cpu idle%。如果發現cpu占用過高,則c, shift+h, shift + p查看線程占用CPU情況,并記錄
  2. free: 查看內存情況,如果剩余量較小,則top中shift+m查看內存占用情況,并記錄
  3. 如果top中發現占用資源較多的進程名稱(例如java這樣的通用名稱)不太能說明進程身份,則要用ps xuf | grep java等方式記錄下具體進程的身份
  4. 取jstack結果。假如取不到,嘗試加/F
    jstack命令:jstack PID > jstack.log
  5. jstat查看OLD區占用率。如果占用率到達或接近100%,則jmap取結果。假如取不到,嘗試加/F
    jstat命令: jstat -gcutil PID
    S0 S1 E O P YGC YGCT FGC FGCT GCT
    0.00 21.35 88.01 97.35 59.89 111461 1904.894 1458 291.369 2196.263
    jmap命令: ** jmap -dump:file=dump.map PID**
  6. 重啟服務

七、參考資料
BTrace官網
MAT官網
使用jmap和MAT觀察Java程序內存數據
使用Eclipse遠程調試Java應用程序
Linux下輸入【man strace/top/iostat/vmstat/netstat/jstack】

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,533評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,055評論 3 414
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事?!?“怎么了?”我有些...
    開封第一講書人閱讀 175,365評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,561評論 1 307
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,346評論 6 404
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 54,889評論 1 321
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 42,978評論 3 439
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,118評論 0 286
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,637評論 1 333
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,558評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,739評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,246評論 5 355
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 43,980評論 3 346
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,362評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,619評論 1 280
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,347評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,702評論 2 370

推薦閱讀更多精彩內容