天天看點

Java 程式性能優化《第一章》Java性能調優概述 1.1性能概述

為什麼程式總是那麼慢?它現在到底在幹什麼?時間都花在哪裡了?也許,你經常會抱怨這些問題,如果是這樣,那說明你的程式出了性能問題。和功能問題相比,性能問題在有些情況下,可能不算什麼大問題,将就将就,也就過去了。但是嚴重的性能問題會導緻程式癱瘓、假死、直至崩潰。本書就先來認識性能的各種表現和名額。

對用戶端程式而言,拙劣的性能會嚴重影響使用者體驗,界面停頓、抖動、響應遲鈍等問題會遭到使用者不停地抱怨。一個典型的例子就是eclipse ide工具在full gc時會出現程式假死的現象,相信一定被不少開發人員所诟病。對于伺服器程式來說,性能問題則更為重要,相信不少背景伺服器軟體都有各自的性能目标。以web伺服器為例,伺服器的響應時間、吞吐量就是兩個重要的性能參數。當伺服器承受巨大的通路壓力時,可能出現響應時間變長、吞吐量下降,甚至是抛出記憶體溢出異常而崩潰,這些問題,都是性能調優需要解決的。

一般來說,程式的性能通過以下幾個方面表現:

執行速度:程式的反應是否迅速,響應時間是否足夠短。

記憶體配置設定:記憶體配置設定是合理的,是否過多的消耗記憶體或者存在洩露。

啟動時間:程式從運作到可以正常處理業務需要花費多長時間。

負載承受能力:當系統壓力上升時,系統的執行速度、響應時間的上升曲線是否平緩。

為了能夠科學的進行性能分析,對性能名額進行定量評測是非常重要的。目前,一些可以用于定量評測的性能名額有:

執行時間:一段代碼開始運作到運作結束,所使用的時間。

cpu時間:函數或者線程占用cpu的時間。

記憶體配置設定:程式在運作時占用的記憶體空間。

磁盤吞吐量:描述i/o的使用情況。

網絡吞吐量:描述網絡的使用情況。

響應時間:系統對某使用者行為或者事件做出響應的時間。響應時間越短,性能越好。

木桶原理又稱 ”短闆理論“ ,其核心思想是:一隻木桶盛水的多少,并不取決于桶壁上最高的那塊木頭,而是取決于桶壁上最短的那塊,如圖1.1所示。

Java 程式性能優化《第一章》Java性能調優概述 1.1性能概述

圖1.1 木桶原理示意圖

将這個理論應用到系統性能優化上,可以這麼了解,即使系統擁有充足的記憶體資源和cpu資源,但是如果磁盤i/o性能低下,那麼系統的總體性能取決于目前最慢的磁盤i/o速度,而不是目前最優越的cpu或者記憶體。這這種情況下,如果需要進一步提升系統性能,優化記憶體或者cpu資源是毫無用處的。隻有提高磁盤i/o性能才能對系統的整體性能進行優化。而此時,磁盤i/o就是系統的性能瓶頸。

ps:根據木桶原理,系統的最終性能取決于系統中性能表現最差的元件。是以,為了提升系統整體性能,必須對系統中表現最差的元件進行優化,而不是對系統中表現良好的元件進行優化。

根據應用的特點不同,任何計算機資源都有可能成為系統瓶頸。其中,最有可能成為系統瓶頸的計算資源如下。

磁盤i/o:由于磁盤i/o讀寫的速度要比記憶體慢很多,程式在運作過程中,如果需要等待磁盤i/o完成,那麼低效的i/o操作會拖累整個系統。

網絡操作:對網絡資料進行讀寫的情況與磁盤i/o類似。由于網絡環境下的不正确性,尤其是對網際網路上資料的讀寫,網絡操作的速度可能比本地磁盤i/o更慢。是以如不加特殊處理,也極有可能成為系統瓶頸。

cpu:對計算資源要求較高的應用,由于其長時間、不間斷的大量占用cpu資源,那麼對cpu的争奪将導緻性能問題。如科學計算、3d渲染等對cpu需求旺盛的應用。

異常:對java應用來說,異常的捕獲和處理是非常消耗資源的。如果程式高頻率地進行異常處理,則整體性能便會有明顯下降。

資料庫:大部分應用程式都離不開資料庫,而海量資料的讀寫操作可能是相當費時的。而應用程式可能需要等待資料庫操作完成或者傳回請求的結果集,那麼緩慢的同步操作将成為系統瓶頸。

鎖競争:對高并發程式來說,如果存在激烈的鎖競争,無疑是對性能極大的打擊。鎖競争明顯會增加線程上下文切換的開銷,而且,這些開銷都是與應用需求無關的系統開銷,白白占用寶貴的cpu資源,卻不帶來任何好處。

記憶體:一般來說,隻要應用程式設計合理,記憶體在讀寫速度上不太可能成為性能瓶頸。除非應用程式進行了高頻率的記憶體交換和掃描,但這些情況比較少見,使記憶體制約系統性能最可能的情況是記憶體大小不足,與磁盤相比,記憶體的大小似乎小的可憐,這意味着應用軟體隻能盡可能将常用的核心資料讀入記憶體,這在一定程度上降低了系統性能。

amdahl 定律是計算機科學中非常重要的定律,它定義了串行系統并行後加速比的計算公式和理論上限。

加速比定義 : 加速比 = 優化前系統消耗 / 優化後系統消耗

所謂加速比,就是優化前耗時與優化後耗時的比值。加速比越高,表明優化效果越明顯。

amdahl 定律給出了加速比與系統并行度和處理器數量的關系。設加速比為 speedup,系統内必須串行化的程式比重為 f,cpu處理器數量為 n,則有:

Java 程式性能優化《第一章》Java性能調優概述 1.1性能概述

根據這個公式,如果cpu處理器數量趨于無窮,那麼加速比與系統的串行化率成反比,如果系統中必須有50%的代碼串行執行,那麼系統的最大加速比為2。

假設有一個程式分為以下步驟執行,每個執行步驟花費100個時間機關,其中,隻有步驟 2 和步驟 5 可以進行并行,步驟 1、3、4必須串行,如圖1.2所示。在全串行的情況下,系統合計耗時500個時間機關。

Java 程式性能優化《第一章》Java性能調優概述 1.1性能概述
Java 程式性能優化《第一章》Java性能調優概述 1.1性能概述

圖1.2 串行工作流程

若将步驟 2 和步驟 5 并行化,假設在雙處理器上,則有如圖1.3所示的處理流程。在這種情況下,步驟 2 和步驟 5 的耗時為50個機關。故系統整體耗時為400個時間機關。根據加速比的定義有:

加速比 = 優化前系統耗時 / 優化後系統耗時 = 500 / 400 = 1.25

或者前文中給出的加速比公式。由于5個步驟中,3個步驟必須串行,是以其串行的比重為3/5=0.6 即f=0.6,且雙核處理器個數n為2。帶入公式得:

加速比 = 1 /(0.6 + (1-0.6) / 2 = 1.25

Java 程式性能優化《第一章》Java性能調優概述 1.1性能概述
Java 程式性能優化《第一章》Java性能調優概述 1.1性能概述

圖1.3 雙核處理器上的并行化

在極端情況下,假設并行處理器個數為無窮大,則有如圖1.4所示的處理過程。步驟 2 和步驟 5 的處理時間趨于 0 。即使這樣,系統整體耗時依然大于300個時間機關。即加速比的極限為 500 / 300 = 1.67。

Java 程式性能優化《第一章》Java性能調優概述 1.1性能概述
Java 程式性能優化《第一章》Java性能調優概述 1.1性能概述

圖1.4 極端情況下的并行化

使用加速比計算公式,n 趨于無窮大,有 speedup = 1/f,且 f=0.6,故有 speedup = 1.67。

由此可見,為了提高系統的速度,僅增加cpu處理器的數量并不一定能夠起到有效地作用,需要從根本上修改程式的串行行為,提高系統内可并行化的子產品比重,在此基礎上,合理增加并行處理器數量,才能以最小的投入,得到最大的加速比。

ps:根據 amdahl 定律,使用多核cpu對系統進行優化,優化的效果取決于cpu的數量以及系統中的串行化程式比重。cpu數量越多,串行化比重越低,則優化效果越好。僅提高cpu數量而不降低程式的串行化比重,也無法提高系統性能。