明輝手游網(wǎng)中心:是一個免費(fèi)提供流行視頻軟件教程、在線學(xué)習(xí)分享的學(xué)習(xí)平臺!

Java性能

[摘要]Java語言特別強(qiáng)調(diào)準(zhǔn)確性,但可靠的行為要以性能作為代價。這一特點(diǎn)反映在自動收集垃圾、嚴(yán)格的運(yùn)行期檢查、完整的字節(jié)碼檢查以及保守的運(yùn)行期同步等等方面。對一個解釋型的虛擬機(jī)來說,由于目前有大量平臺可供挑選,所以進(jìn)一步阻礙了性能的發(fā)揮。   “先做完它,再逐步完善。幸好需要改進(jìn)的地方通常不會太多!保...

  Java語言特別強(qiáng)調(diào)準(zhǔn)確性,但可靠的行為要以性能作為代價。這一特點(diǎn)反映在自動收集垃圾、嚴(yán)格的運(yùn)行期檢查、完整的字節(jié)碼檢查以及保守的運(yùn)行期同步等等方面。對一個解釋型的虛擬機(jī)來說,由于目前有大量平臺可供挑選,所以進(jìn)一步阻礙了性能的發(fā)揮。
  “先做完它,再逐步完善。幸好需要改進(jìn)的地方通常不會太多!保⊿teve McConnell的《About performance》[16])
  本附錄的宗旨就是指導(dǎo)大家尋找和優(yōu)化“需要完善的那一部分”。

  D.1 基本方法
  只有正確和完整地檢測了程序后,再可著手解決性能方面的問題:
  (1) 在現(xiàn)實(shí)環(huán)境中檢測程序的性能。若符合要求,則目標(biāo)達(dá)到。若不符合,則轉(zhuǎn)到下一步。
  (2) 尋找最致命的性能瓶頸。這也許要求一定的技巧,但所有努力都不會白費(fèi)。如簡單地猜測瓶頸所在,并試圖進(jìn)行優(yōu)化,那么可能是白花時間。
  (3) 運(yùn)用本附錄介紹的提速技術(shù),然后返回步驟1。

  為使努力不至白費(fèi),瓶頸的定位是至關(guān)重要的一環(huán)。Donald Knuth[9]曾改進(jìn)過一個程序,那個程序把50%的時間都花在約4%的代碼量上。在僅一個工作小時里,他修改了幾行代碼,使程序的執(zhí)行速度倍增。此時,若將時間繼續(xù)投入到剩余代碼的修改上,那么只會得不償失。Knuth在編程界有一句名言:“過早的優(yōu)化是一切麻煩的根源”(Premature optimization is the root of all evil)。最明智的做法是抑制過早優(yōu)化的沖動,因?yàn)槟菢幼隹赡苓z漏多種有用的編程技術(shù),造成代碼更難理解和操控,并需更大的精力進(jìn)行維護(hù)。

  D.2 尋找瓶頸
  為找出最影響程序性能的瓶頸,可采取下述幾種方法:

  D.2.1 安插自己的測試代碼
  插入下述“顯式”計(jì)時代碼,對程序進(jìn)行評測:

  long start = System.currentTimeMillis();
  // 要計(jì)時的運(yùn)算代碼放在這兒
  long time = System.currentTimeMillis() - start;

  利用System.out.println(),讓一種不常用到的方法將累積時間打印到控制臺窗口。由于一旦出錯,編譯器會將其忽略,所以可用一個“靜態(tài)最終布爾值”(Static final boolean)打開或關(guān)閉計(jì)時,使代碼能放心留在最終發(fā)行的程序里,這樣任何時候都可以拿來應(yīng)急。盡管還可以選用更復(fù)雜的評測手段,但若僅僅為了量度一個特定任務(wù)的執(zhí)行時間,這無疑是最簡便的方法。
  System.currentTimeMillis()返回的時間以千分之一秒(1毫秒)為單位。然而,有些系統(tǒng)的時間精度低于1毫秒(如Windows PC),所以需要重復(fù)n次,再將總時間除以n,獲得準(zhǔn)確的時間。

  D.2.2 JDK性能評測[2]
  JDK配套提供了一個內(nèi)建的評測程序,能跟蹤花在每個例程上的時間,并將評測結(jié)果寫入一個文件。不幸的是,JDK評測器并不穩(wěn)定。它在JDK 1.1.1中能正常工作,但在后續(xù)版本中卻非常不穩(wěn)定。
  為運(yùn)行評測程序,請?jiān)谡{(diào)用Java解釋器的未優(yōu)化版本時加上-prof選項(xiàng)。例如:
  java_g -prof myClass
  或加上一個程序片(Applet):
  java_g -prof sun.applet.AppletViewer applet.html
  理解評測程序的輸出信息并不容易。事實(shí)上,在JDK 1.0中,它居然將方法名稱截短為30字符。所以可能無法區(qū)分出某些方法。然而,若您用的平臺確實(shí)能支持-prof選項(xiàng),那么可試試Vladimir Bulatov的“HyperPorf”[3]或者Greg White的“ProfileViewer”來解釋一下結(jié)果。

  D.2.3 特殊工具
  如果想隨時跟上性能優(yōu)化工具的潮流,最好的方法就是作一些Web站點(diǎn)的?汀1热缬蒍onathan Hardwick制作的“Tools for Optimizing Java”(Java優(yōu)化工具)網(wǎng)站:
  http://www.cs.cmu.edu/~jch/java/tools.html

  D.2.4 性能評測的技巧
  ■由于評測時要用到系統(tǒng)時鐘,所以當(dāng)時不要運(yùn)行其他任何進(jìn)程或應(yīng)用程序,以免影響測試結(jié)果。
  ■如對自己的程序進(jìn)行了修改,并試圖(至少在開發(fā)平臺上)改善它的性能,那么在修改前后應(yīng)分別測試一下代碼的執(zhí)行時間。
  ■盡量在完全一致的環(huán)境中進(jìn)行每一次時間測試。
  ■如果可能,應(yīng)設(shè)計(jì)一個不依賴任何用戶輸入的測試,避免用戶的不同反應(yīng)導(dǎo)致結(jié)果出現(xiàn)誤差。

  D.3 提速方法
  現(xiàn)在,關(guān)鍵的性能瓶頸應(yīng)已隔離出來。接下來,可對其應(yīng)用兩種類型的優(yōu)化:常規(guī)手段以及依賴Java語言。

  D.3.1 常規(guī)手段
  通常,一個有效的提速方法是用更現(xiàn)實(shí)的方式重新定義程序。例如,在《Programming Pearls》(編程拾貝)一書中[14],Bentley利用了一段小說數(shù)據(jù)描寫,它可以生成速度非?、而且非常精簡的拼寫檢查器,從而介紹了Doug McIlroy對英語語言的表述。除此以外,與其他方法相比,更好的算法也許能帶來更大的性能提升——特別是在數(shù)據(jù)集的尺寸越來越大的時候。欲了解這些常規(guī)手段的詳情,請參考本附錄末尾的“一般書籍”清單。

  D.3.2 依賴語言的方法
  為進(jìn)行客觀的分析,最好明確掌握各種運(yùn)算的執(zhí)行時間。這樣一來,得到的結(jié)果可獨(dú)立于當(dāng)前使用的計(jì)算機(jī)——通過除以花在本地賦值上的時間,最后得到的就是“標(biāo)準(zhǔn)時間”。

  運(yùn)算 示例 標(biāo)準(zhǔn)時間

  本地賦值 i=n; 1.0
  實(shí)例賦值 this.i=n; 1.2
  int增值 i++; 1.5
  byte增值 b++; 2.0
  short增值 s++; 2.0
  float增值 f++; 2.0
  double增值 d++; 2.0
  空循環(huán) while(true) n++; 2.0
  三元表達(dá)式 (x<0) ?-x : x 2.2
  算術(shù)調(diào)用 Math.abs(x); 2.5
  數(shù)組賦值 a[0] = n; 2.7
  long增值 l++; 3.5
  方法調(diào)用 funct(); 5.9
  throw或catch異常 try{ throw e; }或catch(e){} 320
  同步方法調(diào)用 synchMehod(); 570
  新建對象 new Object(); 980
  新建數(shù)組 new int[10]; 3100

  通過自己的系統(tǒng)(如我的Pentium 200 Pro,Netscape 3及JDK 1.1.5),這些相對時間向大家揭示出:新建對象和數(shù)組會造成最沉重的開銷,同步會造成比較沉重的開銷,而一次不同步的方法調(diào)用會造成適度的開銷。參考資源[5]和[6]為大家總結(jié)了測量用程序片的Web地址,可到自己的機(jī)器上運(yùn)行它們。



標(biāo)簽:Java性能