
Java程序調(diào)優(yōu)入門級教程,看似很厚,其實書很薄,國內(nèi)高手寫的,當(dāng)然有一些內(nèi)容有抄襲的嫌疑,適合java開發(fā)經(jīng)驗不太足的,一般的高手,此類技能應(yīng)該必須具備了。我看的時候花了兩周,總結(jié)起來如下,純干貨(不包括JVM部分,因為個人覺得JVM學(xué)習(xí)看《深入理解Java虛擬機(jī)》):
1.常見的系統(tǒng)瓶頸因素:磁盤I/O,網(wǎng)絡(luò)操作,CPU,java異常捕獲及處理,數(shù)據(jù)庫讀寫,鎖競爭,GC
2.加速比Speedup<=1/(F+(1-F)/N),F為串行計算的比例,N為CPU邏輯數(shù)
3.調(diào)優(yōu)層次:設(shè)計調(diào)優(yōu)--->代碼調(diào)優(yōu)--->JVM參數(shù)調(diào)優(yōu)--->數(shù)據(jù)庫調(diào)優(yōu)--->OS調(diào)優(yōu),當(dāng)實際應(yīng)用出現(xiàn)瓶頸需要調(diào)優(yōu)時,一般的步驟是:代碼--->JVM參數(shù)--->數(shù)據(jù)庫--->OS--->應(yīng)用架構(gòu)(設(shè)計)
4.設(shè)計調(diào)優(yōu)的常見招數(shù):
1:多用設(shè)計模式(單例,享元,觀察者,訪問者,裝飾者,代理等)
2:Buffer/Cache,緩沖/緩存思想
3:多線程并行代替串行(要求一般串行間沒有因果或前后關(guān)系)
4:應(yīng)用負(fù)載均衡(JVM級,需要處理好共享數(shù)據(jù)的一致性問題)
5:時間/空間的轉(zhuǎn)換
6:使用ValueObject減少計算或請求次數(shù)
5.代碼優(yōu)化的幾個簡單切入點:
0):不要在循環(huán)體里定義引用并創(chuàng)建對象,將定義引用放到外面
Object obj = null;
for (int i = 0; i < 10000; ++i) {
(Object) obj = new Object();
System.out. } 1):避免重復(fù)初始化對象 public class A { public A() { table = new Hashtable(); // 將Hashtable對象table初始化了兩次 } } 1):字符串優(yōu)化的幾個地方 a:substring()方法速度很快,但是容易引起內(nèi)存溢出問題,因為會保留對原串的引用,所以建議用new String(***.substring(參數(shù)))的模式 b:對字符串截取可用split,但速度快的可以考慮StringTokenizer(sun不建議使用),最好用indexOf+substring自己實現(xiàn)截取 c:對字符串的開頭/結(jié)尾子串判斷一般用startsWith/endsWith,由于他們和split一樣是基于正則的,所有最好用charAt來自己實現(xiàn)更快 d:對字符串的相加,StringBuild最優(yōu),StringBuffer次之(線程安全),String.concat再次之,+/+=最次(不考慮靜態(tài)常量編譯器的優(yōu)化) 2):ArrayList(Vector)與LinkedList比較 a:ArrayList基于數(shù)組(一塊連續(xù)的內(nèi)存空間),LinkedList基于雙向鏈表,因此ArrayList的主要性能耗在擴(kuò)展空間時數(shù)據(jù)復(fù)制,而LinkedList耗在數(shù)據(jù)遍歷(尤其是找中間的數(shù)據(jù)) b:頭尾的新增/刪除對LinkedList沒有壓力,但是每次隨機(jī)訪問需要從頭查找,會要親命 c:在尾部添加對ArrayList沒有壓力,但從頭部刪除都會數(shù)組復(fù)制,會要親命。 d:對LinkedList的遍歷,要么用for-Each,要么Iterator,不要用普通的ini i=0;i<size;i++,因為get(i)是隨機(jī)查找,每次都從頭或尾遍歷,會要親命 e:一般實現(xiàn)了Randomaccessprivate Hashtable table = new Hashtable ();
3):HashMap如果key是一個個重寫了hashCode方法的對象,如果此hashCode方法放回相同的int值,則每次放入不同對象會到同一個桶下,遍歷查找很慢
4):HashMap底層用了數(shù)組實現(xiàn),使用大于等于initialCapacity并且是2的指數(shù)次冪作為數(shù)組大小,threshold為當(dāng)前數(shù)組總?cè)萘颗c負(fù)載因子的乘積,即閥值,當(dāng)實際容量超閥值 時會進(jìn)行數(shù)組擴(kuò)展復(fù)制,因此適當(dāng)?shù)膇nitialCapacity有利于提高性能。
5):LinkedHashMap基于元素進(jìn)入順序或被訪問先后順序(被訪問的元素放到最后),而TreeMap基于傳入的Comparetor參數(shù)或?qū)崿F(xiàn)了Comparable的key對象進(jìn)行排序,適用范圍 不一樣。HashSet,LinkedHashSet,TreeSet是對應(yīng)Map的簡單封裝。
6):使用NIO(ByteBuffer+Channel)可以提升I/O讀寫速率,注意duplicate(),asReadOnlyBuffer(),slice()都是共享原始緩存數(shù)據(jù)的,一般用文件內(nèi)存映射MappedByteBuffer,結(jié)構(gòu) 化散射接口ScatteringByteChannel,結(jié)構(gòu)化聚集接口GatheringByteChannel將多個ByteBuffer組成一個數(shù)組一次寫入,用DirectBuffer代替ByteBuffer進(jìn)行多次讀寫都可以提高效 率,但DirectBuffer是直接開辟OS內(nèi)存,如果頻繁新建回收,性能反而不如ByteBuffer虛擬機(jī)內(nèi)的相同操作.
7):4個引用級別:強(qiáng),軟,弱,虛,其作用分別不同,一般軟和弱引用可以作為緩存的一種方案避免內(nèi)存溢出,而虛更多用于跟蹤對象回收時機(jī),弱引用WeakHashMap可以 作為簡單的緩存對象。
8):不在循環(huán)代碼中使用try-catch,盡量放到循環(huán)體外,多用局部變量或臨時變量存儲計算值以避免重復(fù)計算,可以考慮在一次循環(huán)中做多個操作減少循環(huán)次數(shù)(i+1,i+2,i+3...),多 用"阻斷性"邏輯運(yùn)算如&&來代替位運(yùn)算如&(當(dāng)然一般也不建議利用條件判斷來做一些操作,因此后面的判斷默認(rèn)應(yīng)該可以不去運(yùn)行的)
9):多用一維數(shù)組代替二維數(shù)組;使用Buffer進(jìn)行I/O;對構(gòu)造成本大的函數(shù),用clone代替new(注意該類實現(xiàn)Cloneable,并且默認(rèn)是淺復(fù)制,深復(fù)制需要自己重寫Object的clone 方法)
10):技巧:用位運(yùn)算代替2次冪的乘除;多用static靜態(tài)方法而不是實例方法;多用native方法如arrayCopy等;
來自為知筆記(Wiz)
新聞熱點
疑難解答