Java語(yǔ)言特別強調準確性,但可靠的行為要以性能作為代價(jià)。這一特點(diǎn)反映在自動(dòng)收集垃圾、嚴格的運行期檢查、完整的字節碼檢查以及保守的運行期同步等等方面。對一個(gè)解釋型的虛擬機來(lái)說(shuō),由于目前有大量平臺可供挑選,所以進(jìn)一步阻礙了性能的發(fā)揮。
“先做完它,再逐步完善。幸好需要改進(jìn)的地方通常不會(huì )太多!
本附錄的宗旨就是指導大家尋找和優(yōu)化“需要完善的那一部分”。
D.1 基本方法
只有正確和完整地檢測了程序后,再可著(zhù)手解決性能方面的問(wèn)題:
(1) 在現實(shí)環(huán)境中檢測程序的性能。若符合要求,則目標達到。若不符合,則轉到下一步。
(2) 尋找最致命的性能瓶頸。這也許要求一定的技巧,但所有努力都不會(huì )白費。如簡(jiǎn)單地猜測瓶頸所在,并試圖進(jìn)行優(yōu)化,那么可能是白花時(shí)間。
(3) 運用本附錄介紹的提速技術(shù),然后返回步驟1。
為使努力不至白費,瓶頸的定位是至關(guān)重要的一環(huán)。Donald Knuth[9]曾改進(jìn)過(guò)一個(gè)程序,那個(gè)程序把50%的時(shí)間都花在約4%的代碼量上。在僅一個(gè)工作小時(shí)里,他修改了幾行代碼,使程序的執行速度倍增。此時(shí),若將時(shí)間繼續投入到剩余代碼的修改上,那么只會(huì )得不償失。Knuth在編程界有一句名言:“過(guò)早的優(yōu)化是一切麻煩的根源”(Premature optimization is the root of all evil)。最明智的做法是抑制過(guò)早優(yōu)化的沖動(dòng),因為那樣做可能遺漏多種有用的編程技術(shù),造成代碼更難理解和操控,并需更大的精力進(jìn)行維護。
D.2 尋找瓶頸
為找出最影響程序性能的瓶頸,可采取下述幾種方法:
D.2.1 安插自己的測試代碼
插入下述“顯式”計時(shí)代碼,對程序進(jìn)行評測:
long start = System.currentTimeMillis();
// 要計時(shí)的運算代碼放在這兒
long time = System.currentTimeMillis() - start;
利用System.out.println(),讓一種不常用到的方法將累積時(shí)間打印到控制臺窗口。由于一旦出錯,編譯器會(huì )將其忽略,所以可用一個(gè)“靜態(tài)最終布爾值”(Static final boolean)打開(kāi)或關(guān)閉計時(shí),使代碼能放心留在最終發(fā)行的程序里,這樣任何時(shí)候都可以拿來(lái)應急。盡管還可以選用更復雜的評測手段,但若僅僅為了量度一個(gè)特定任務(wù)的執行時(shí)間,這無(wú)疑是最簡(jiǎn)便的方法。
System.currentTimeMillis()返回的時(shí)間以千分之一秒(1毫秒)為單位。然而,有些系統的時(shí)間精度低于1毫秒(如Windows PC),所以需要重復n次,再將總時(shí)間除以n,獲得準確的時(shí)間。
D.2.2 JDK性能評測[2]
JDK配套提供了一個(gè)內建的評測程序,能跟蹤花在每個(gè)例程上的時(shí)間,并將評測結果寫(xiě)入一個(gè)文件。不幸的是,JDK評測器并不穩定。它在JDK 1.1.1中能正常工作,但在后續版本中卻非常不穩定。
為運行評測程序,請在調用Java解釋器的未優(yōu)化版本時(shí)加上-prof選項。例如:
文章來(lái)源于領(lǐng)測軟件測試網(wǎng) http://kjueaiud.com/