該BLOG內容是之前在部門組織討論運行時問題時自己寫的PPT內容,內容以點帶面,主要是方便以后自己回顧查看。
大綱包括:1、運行時問題分類 2、服務器自帶工具 3、其他工具 4、例子 5、實際情況
運行時問題分類-軟件角度:1、內存泄漏,對象未釋放 2、線程阻塞、死鎖 3、線程死循環 4、網絡IO連接超時時間過長 5、磁盤不可寫 .....
運行時問題分類-硬件角度:1、內存占用高 2、CPU占用高 3、網絡無反應 4、硬盤空間滿 ....
Linux指令:1、top, top -Hp pid 2、free 3、df 4、netstat, netstat -natp ...
JDK指令:1、jps, jps -v 2、jstack, jstack pid 3、jmap, jmap -dump:format=b,file=/opt/... 4、jstat, jstat -gcutil(gc,gccapacity) pid ....
工具:
實時分析工具: 1、Jconsole 2、VisualVM 3、JProfiler 4、JavaMelody 5、LambdaProbe ....
離線分析工具: 1、MemoryAnalyzer tool 2、Thread Dump Analyzer ....
DEMO:1、內存溢出 2、CPU占用過高 3、線程死鎖 4、線程阻塞
准備工作:堆棧內存設置低一點,打印GC日志和OOM時輸出dump文件: set JAVA_OPTS=-server -Xms24m -Xmx50m -XX:PermSize=28M -XX:MaxPermSize=80m -XX:+PrintGCDetails -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=d:\temp\dump
內存溢出:
Map<String, Person> map = new HashMap<String, Person>(); Object[] array = new Object[1000000]; for (int i = 0; i < 1000000; i++) { String d = new Date().toString(); Person p = new Person(d, i); map.put(i + "person", p); array[i] = p; }





MAT-關鍵字(個人理解,不一定准確):
Histogram:內存中的類對象實例的對象的個數和大小
Dominator Tree:堆對象樹,對象大小和占用百分比
Leak Suspects:MAT分析的內存泄漏的可疑點
shallow heap:對象自身占用內存大小
retained heap:對象自身和引用的對象占用內存大小
Merge Shortest Paths to GC Roots:從GC根節點到該對象的路徑視圖
with outgoing references:對象持有的外部對象引用
with incomming references:對象被哪些外部對象引用
....
CPU占用過高:
int i = 0;
while (i < 1000000) {
i++;
System.out.println(i);
try {
Thread.sleep(0);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}

線程死鎖:
Thread t1 = new Thread(new SyncThread(obj1, obj2), "t1");
Thread t2 = new Thread(new SyncThread(obj2, obj1), "t2");
t1.start();
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
t2.start();
synchronized (obj1) {
System.out.println("主線程 lock on " + obj1.getName());
}
private Person obj1;
private Person obj2;
public SyncThread(Person o1, Person o2) {
this.obj1 = o1;
this.obj2 = o2;
}
public void run() {
String name = Thread.currentThread().getName();
System.out.println(name + " acquiring lock on " + obj1.getName());
synchronized (obj1) {
System.out.println(name + " acquired lock on " + obj1.getName());
work();
System.out.println(name + " acquiring lock on " + obj2.getName());
synchronized (obj2) {
System.out.println(name + " acquired lock on " + obj2.getName());
work();
}
System.out.println(name + " released lock on " + obj2.getName());
}
System.out.println(name + " released lock on " + obj1.getName());
System.out.println(name + " finished execution.");
}
private void work() {
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}


線程阻塞:
WaitThread thread1 = new WaitThread();
thread1.setName("線程1");
NotifyThread thread2 = new NotifyThread();
thread2.setName("線程2");
thread1.start();
try {
Thread.sleep(20000);
} catch (InterruptedException e) {
e.printStackTrace();
}
thread2.start();
public class NotifyThread extends Thread {
@Override
public void run() {
synchronized (RequestThreadWait.object) {
System.out.println("線程" + Thread.currentThread().getName() + "占用了鎖");
try {
Thread.sleep(20000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
RequestThreadWait.object.notify();
System.out.println("線程" + Thread.currentThread().getName() + "調用了object.notify()");
try {
Thread.sleep(20000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
System.out.println("線程" + Thread.currentThread().getName() + "釋放了鎖");
}
}
public class WaitThread extends Thread {
public void run() {
synchronized (RequestThreadWait.object) {
System.out.println("線程" + Thread.currentThread().getName() + "獲取到了鎖開始");
try {
RequestThreadWait.object.wait();
} catch (InterruptedException e) {
}
System.out.println("線程" + Thread.currentThread().getName() + "獲取到了鎖結束!");
}
}
}


線程狀態(個人理解,不一定准確):
WAITING (parking):線程自身掛起等待,正常
WAITING (on object monitor):線程主動執行wait,等待資源,如果是自己的程序,需要關注
BLOCKED (on object monitor):線程阻塞,等待對方釋放資源,如果是互相等待對方阻塞的線程,則發生死鎖
TIMED_WAITING (on object monitor):線程調用了wait(long timeout),在特定時間內等待
TIMED_WAITING (sleeping):調用了sleeping,休眠一段時間
JavaMelody:

LambdaProbe

實際情況:
用戶反饋各種千奇百怪的問題!
網絡訪問連接不上
網站、接口訪問超時
特定功能很慢
部分功能部分人打不開
.......
->
ping,telnet,traceroute....
top,top -Hp pid,jstack pid....
jstat -gc,gcutil,gccapacity pid...
jmap -dump:format=b,file=/opt/.... tail, df -lh....
netstat -natp....
.....
生產問題沒有統一解決辦法,具體問題具體分析
內存查看:jstat

線程情況查看:top -Hp pid

CPU查看:jstack

網絡查看:netstat

實際問題分析:
線上查看 服務器情況分析 獲取內存dump 獲取javacore
線下分析 工具調試分析內存線程
代碼調試 Eclipse Class Decompiler(自動反編譯,選擇JD-Core,精確行數)
...
轉載請注明:http://lawson.cnblogs.com
上面是實際生產問題的自己寫的PPT,copy下來的,JDK自帶的工具和指令比較強大,本篇文章沒有太多介紹。
