# 性能優化攻略
為什么程序總是那么慢?它現在到底在干什么?時間都花到哪去了?也許,你經常會抱怨這些問題。如果是這樣,那說明你的程序出了性能問題。和功能性問題相比,性能問題在有些情況下,可能并不算太大的問題,將就將就,也就過去了。但是,嚴重的性能問題會導致程序癱瘓、假死,甚至崩潰。
### 看懂程序的性能
**a.執行速度**
? 程序的反應是否迅速,響應時間是否足夠短。
**b.內存分配**
? 內存分配是否合理,是否過多地消耗內存或者存在泄露。
**c.啟動時間**
?? 程序從運行到可以正常處理業務需要花費多少時間。
**d.負載承受能力**
? 當系統壓力上升時,系統的執行速度、響應時間的上升曲線是否平緩。
### 性能的參考指標
**a.執行時間**
?? 一段代碼從開始運行到運行結束,所使用的時間。
**b.CPU時間**
?? 函數或者線程占用CPU的時間。
**c.內存分配**
?? 程序在運行時占用的內存空間。
**d.磁盤吞吐量**
?? 描述I/O的使用情況。
**e.網絡吞吐量**
?? 描述網絡的使用情況。
**f.響應時間**
?? 系統對某用戶行為或者事件做出響應的時間。響應時間越短,性能越好。
### 木桶原理與性能瓶頸
木桶原理又稱“短板理論”,其核心思想是:一只木桶盛水的多少,并不取決于桶壁上最高的那塊木塊,而是取決于桶壁上最短的那塊。
根據木桶原理,系統的最終性能瓶頸取決于系統中性能表現最差的組件。因此,為了提升系統整體性能,必須對系統中表現最差的組件進行優化,而不是對系統中表現良好的組件進行優化。
根據應用的特點不同,任何計算機資源都有可能成為系統瓶頸。其中,最有可能成為系統瓶頸的計算資源如下:
**a.磁盤I/O**
由于磁盤I/O讀寫的速度要比內存慢很多,程序在運行過程中,如果需要等待磁盤I/O完成,那么低效的I/O操作會拖累整個系統。
**b.網絡操作**
對網絡數據進行讀寫的情況與磁盤I/O類似。由于網絡環境的不確定性,尤其是互聯網上數據的讀寫,網絡操作的速度可能比本地磁盤I/O更慢。因此,如不加特殊處理,也極可能成為系統瓶頸。
**c.CPU**
對計算機資源要求較高的應用,由于其長時間、不間斷地大量占用CPU資源,那么對CPU的爭奪將導致性能問題。如科學計算、3D渲染等對CPU需求旺盛的應用。
**d.異常**
對Java應用來說,異常的捕獲和處理是非常耗費資源的,如果程序高頻率地進行異常處理,則整理性能便會有明顯下降。
**e.數據庫**
大部分應用程序都離不開數據庫,而海量數據的讀寫操作操作可能是相當費時的。而應用程序可能需要等待數據庫操作完成或者返回請求的結果集,那么緩存的同步操作將成為系統瓶頸。
**f.鎖競爭**
對高并發程序來說,如果存在激烈的鎖競爭,無疑是對性能極大的打擊。鎖競爭將會明顯增加線程上下文切換的開銷。而且,這些開銷都是與應用需求無關的系統開銷,白白占用寶貴的CPU資源,去不帶來任何好處。
**g.內存**
一般來說,只要應用程序設計合理,內存在讀寫速度上不太可能成為系統瓶頸。除非應用程序進行了高頻率的內存交換和掃描,但這些情況比較少見。使內存制約系統性能瓶頸的情況是內存大小不足。與磁盤相比,內存的大小似乎小的可憐,這意味著應用軟件只能盡可能將常用的核心數據讀入內存,這在一定程序上降低了系統性能。
### Amadahl定律
Amadahl定律是計算機科學中非常重要的定律,它定義了串行系統并行化后加速比的計算公式和理論上限。
加速比定義:加速比=優化前系統耗時/優化后系統耗時
加速比越高,表明優化效果越明顯。
Amadahl定律給出了加速比與系統并行度和處理器數量的關系。
設加速比為Speedup,系統內必須串行化的程序比重為F,CPU數量為N,則有:
Speedup<= 1/ (F+ (1-F) /N)
根據這個公式,如果CPU數量趨于無窮,那么加速比與系統的串行化成反比。如果系統中必須有50%的代碼穿行執行,那么系統的最大加速比是2。
### 性能調優的層次
#### **a.設計調優**
設計調優處于所有調優手段的上層,它往往需要在軟件開發之前進行。
設計優化的一大顯著特點是,它可以規避某一個組件的性能問題,而非改良該組件的實現,
如果說,代碼優化和JVM優化是對系統微觀層面上“量”的優化,那么設計優化就是對系統在宏觀層面上“質”的優化。
一個良好的系統設計可以規避很多潛在的性能問題。因此,盡可能多花時間在系統設計上,是創建高性能程序的關鍵。
#### **b.代碼調優**
代碼調優涉及諸多編碼技巧,需要開發人員熟悉相關語言的API,并在合適的場景中正確使用相關API或類庫。同時,對算法、數據結構的靈活運用。
雖然代碼優化是從微觀上對性能進行調整,但是一個“好”的實現和一個“壞”的實現對系統的影響還是很大的。比如同樣作為List的實現,LinkedList和ArrayList在隨機訪問上的性能卻可以相差幾個數量級。
作為微觀層面的優化,卻是對系統性能產生直接影響的優化方法。
#### **c.JVM調優**
作為Java軟件的運行平臺,JVM的各項參數將會直接影響Java程序的性能。比如JVM堆的大小、垃圾回收策略。
#### **d.數據庫調優**
可以分為3個部分:
在應用層對SQL語句進行優化;
對數據庫進行優化,比如建立索引;
對數據庫軟件進行優化。
#### **e.操作系統調優**
Windows,Linux。
最大文件句柄數、虛擬內存大小等系統參數對系統性能有影響。
### 基本調優策略和手段
#### 優化的一般步驟
明確目標,通過性能監控和統計工具,觀察和確認當前系統是否已經達到相關目標,若已經達到,則沒有必要再優化;否則,查找當前的系統瓶頸,通過定位相關代碼查找代碼性能問題,其次考慮JVM層、數據庫層或者操作系統。
考慮修改原有設計或者升級硬件也是一種方式。
####系統優化注意事項
性能優化可能對軟件功能、正確性和可維護性造成負面影響。
比如改進算法使得代碼出現了新的Bug,使得代碼更難懂。