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