熱點推薦:
您现在的位置: 電腦知識網 >> 編程 >> Java編程 >> Java高級技術 >> 正文

Java極度性能調整

2013-11-23 19:50:33  來源: Java高級技術 

  有很多介紹基本的Java應用性能調整的文章他們都討論些簡單的技術諸如使用StringBuffer而不用String使用synchronized關鍵字的開銷等等
  
  這篇文章不再介紹這些東西相反我們關注能幫助你的基於Web的應用更快可升級型更好的技巧一些技巧很詳細其他的相對簡短但所有的都很有用最後以一些你可提供給你的管理者的建議結束
  
  我寫這篇文章的靈感來自於當我的同事和我一起回憶我們(dotcom)時代的時候——我們如何設計能支持成千上萬的用戶和擁有緊密代碼的系統我們如何對有侵略性的致命打擊有時在為復用設計和為性能設計之間有一個權衡基於我的情況性能每次都獲勝即使你的商務顧客無需理解代碼復用但是他們知道快速(fastperforming)的系統是怎麼回事讓我們開始看看我們的技巧
  
  如何使用Exception
  Exception降低性能一個異常拋出首先需要創建一個新的對象Throwable接口中的構造器調用名為fillInStackTrace()的本地方法這個方法負責巡檢棧的整個框架來收集跟蹤信息這樣無論何時有異常拋出它要求虛擬機裝載調用棧因為一個新的對象在中部被創建
  
  異常應當僅用於有錯誤發生時而不要控制流
  
  我有機會在一個專門用於無線內容市場的網站(名字故意隱去了)看到一段代碼其中開發者完全可以使用一個簡單的對照來查看對象是否為空相反他或她跳過了這個檢查而實際上拋出NullPointerException
  
  不要兩次初始化變量
  Java通過調用獨特的類構造器默認地初始化變量為一個已知的值所有的對象被設置成nullintegers (byte short int long)被設置成float和double設置成Boolean變量設置成false這對那些擴展自其它類的類尤其重要這跟使用一個新的關鍵詞創建一個對象時所有一連串的構造器被自動調用一樣
  
  對新的關鍵詞使用優選法則
  正如前面提到的通過使用一個新的關鍵詞創建一個類的實例在這個鏈中的所有構造器將被調用如果你需要創建一個類的新實例你可以使用一個實現了cloneable接口的對象的clone()方法該clone方法不調用任何類的構造器
  
  如果你已經使用了設計模式作為你的體系結構的一部分並且使用了工廠模式創建對象變化會很簡單下面所列是工廠模式的典型實現
  
  public static Account getNewAccount() {
  return new Account();
  }
  
  使用了clone方法的refactored代碼看起來可能像下面這樣
  
  private static Account BaseAccount = new Account();
  public static Account getNewAccount() {
    return (Account) BaseAccountclone();
  }
  
  以上的思路對實現數組同樣有用
  
  如果你在應用中沒有使用設計模式我建議你停止讀這篇文章趕快跑到(不要走)書店挑一本四人著的《設計模式》
  
  在任何可能的地方讓類為Final
  標記為final的類不能被擴展在《核心Java API》中有大量這個技術的例子諸如javalangString將String類標記為final阻止了開發者創建他們自己實現的長度方法
  
  更深入點說如果類是final的所有類的方法也是final的Java編譯器可能會內聯所有的方法(這依賴於編譯器的實現)在我的測試裡我已經看到性能平均增加了%
  
  在任何可能的地方使用局部變量
  屬於方法調用部分的自變量和聲明為此調用一部分的臨時變量存儲在棧中這比較快諸如static實例(instance)變量和新的對象創建在堆中這比較慢局部變量的更深入優化依賴於你正在使用的編譯器或虛擬機
  
  使用Nonblocking I/O
  當前的JDK版本不支持nonblocking I/O API很多應用試圖通過創建大量的線程(目光長遠得用在池中)來避免阻塞正如前述在Java中創建線程有嚴重的開銷
  
  典型的你可能看到應用中實現的線程需要支持並發I/O流像Web 服務器並quote and auction components
  
  JDK介紹了一個nonblocking I/O包(javanio)如果你必須保留在較早版本的JDK有添加了支持nonblocking I/O的第三方包
  
  wwwcsberkeleyedu/~mdw/proj/javanbio/l
  
  停止小聰明
  很多開發人員在腦子中編寫可復用和靈活的代碼而有時候在他們的程序中就產生額外的開銷曾經或者另外的時候他們編寫了類似這樣的代碼
  
  public void doSomething(File file) {
  FileInputStream fileIn = new FileInputStream(file);
  // do something
  
  他夠靈活但是同時他們也產生了更多的開銷這個主意背後做的事情是操縱一個InputStream而不是一個文件因此它應該重寫如下
  
  public void doSomething(InputStream inputStream){
  // do something
  
  乘法和除法
  我有太多的東東適用於摩爾法則——它聲明CPU功率每年成倍增長摩爾法則表明每年由開發者所寫的差勁的代碼數量三倍增加劃去了摩爾法則的任何好處
  
  考慮下面的代碼
  
  for (val = ; val < 100000; val +=5) { shiftX = val * 8; myRaise = val * 2; }
  
  如果我們狡猾的利用位移(bit),性能將會六倍增加。tW.WIngWiT.coM這是重寫的代碼:
  
  for (val = 0; val < 100000; val += 5) { shiftX = val << 3; myRaise = val << 1; }
  
  代替了乘以8,我們使用同等效果的左移3位。每一個移動相當於乘以2,變量myRaise對此做了證明。同樣向右移位相當於除以2,當然這會使執行速度加快,但可能會使你的東東以後難於理解;所以這只是個建議。
  
  選擇一個基於垃圾收集實現的虛擬機
  許多人可能會對Java規范不需要實現垃圾收集感到驚訝。設想時代已經是我們都擁有無限內存計算機。總之,垃圾收集器日常事務就是負責發現和拋出(hence garbage)不再需要的對象。垃圾收集必須發現那些對象不再被程序指向,並且使被對象占用的棧內存被釋放掉。它還負責運行任何被釋放對象的finalizer。
  
  垃圾收集故意不允許你釋放並非由你分配的內存,從而幫助你確保程序完整,當JVM確定CPU時間的時間表並且當垃圾收集器運行時,這個進程也產生開銷。
  
  垃圾收集器有兩個不同的步驟執行他們的工作。
  
  實現了定位計算的垃圾收集器在棧中為每一個對象保留一個計數。當一個對象被創建並且對它的一個定位被分配給一個變量,計數增加。當對象越出范圍,定位計數被設置成0並且對象可以被垃圾收集。這個步驟允許參考計數器運行在與程序執行有關的短時間增量內。定位計數在父子彼此擁有定位的應用裡運行不正常。每次一個對象刷新時也會有定位計數增加和減少的開銷。
  
  實現了跟蹤的垃圾收集器從根節點開始跟蹤一列定位。對象發現跟蹤是否被標記。在這個過程完成後,知道不可達的任何沒標記的對象可以被垃圾收集。這可能以位圖(bitmap)形式實現或者在對象中被設置標志。此技術參考"Mark and Sweep."(reference:定位,翻譯成“指向”好像更容易理解,是Java語言對在用對象的一個跟蹤指針。譯者著)
  
  給你的管理人員提建議
  其他方法可被用來使你的基於Web的應用更快並且更可升級。可實現的最簡單的技術通常是支持cluster的策略。使用cluster,一組服務器能夠一起透明的提供服務。多數應用服務器允許你獲得cluster支持而不需要改變你的應用——一個大的勝利。
  
  當然在執行此步驟之前你可能需要考慮來自你使用的應用服務器提供商附加的許可權利。
  
  當看到cluster策略會有許多額外的事情考慮。經常在體系結構中產生的一個缺點是擁有有狀態會話。如果cluster中的一個服務器或者進程當掉,cluster會捨棄整個應用。為防止此類事情發生,cluster必須給cluster中的所有成員不斷復制會話Bean的狀態。確保你也限制了存儲在會話中的對象的大小和數量,因為這些也需要被復制。
  
  Cluster也允許你分期度量你的Web站點的部分。如果你需要度量靜態部分,你可以添加Web服務器。如果你需要度量動態生成的部分,你可以添加應用服務器。
  
  在你已經把你的系統放入cluster後,下一個讓你的應用跑得更快的建議步驟是選擇一個更好的虛擬機。看看Hotspot虛擬機或者其他的飛速發展中的執行優化的虛擬機。隨同虛擬機,看看更好的編譯器是一個更好的主意。
  
  如果你使用了幾個這兒提到的行業技術插件,並且仍然不能獲得你要的可升級性和高可用性,那麼我建議一個可靠的調試策略。策略的第一步是為可能的瓶頸檢查整個體系結構。通常,這在你的作為單線程組件或者有很多輔助連接線組件的UML流圖中很容易識別出來。
  
  最後的步驟是產生一個整個代碼的詳細性能估價。
  
  確保你的管理人員至少為此安排了整個項目時間的20%;否則不足的時間可能不止危及你整個成功的安全,還會導致你向系統引入新的缺點。
  
  許多組織者在適當的位置沒有嚴格意義的測試基礎而歸咎於成本考慮也是錯誤的。確保你的QA環境真實反映你的生產環境,並且你的QA測試考慮以不同的負載測試應用,包括在最大的預期並發用戶時一個基於低負載和一個完全負載的測試。
  
  性能測試,有時測試一個系統的穩定性,可能需要在每天,甚至每周的整個時期的不同關節都運行。
  

From:http://tw.wingwit.com/Article/program/Java/gj/201311/27539.html
    推薦文章
    Copyright © 2005-2013 電腦知識網 Computer Knowledge   All rights reserved.