熱點推薦:
您现在的位置: 電腦知識網 >> 編程 >> Java編程 >> JSP教程 >> 正文

Java性能優化技巧集錦

2013-11-15 11:43:11  來源: JSP教程 

  摘要:
  ===================================
  可供程序利用的資源(內存CPU時間網絡帶寬等)是有限的優化的目的就是讓程序用盡可能少的資源完成預定的任務優化通常包含兩方面的內容減小代碼的體積提高代碼的運行效率本文討論的主要是如何提高代碼的效率
  ===================================
  提綱:
  ===================================
  一通用篇
     不用new關鍵詞創建類的實例
     使用非阻塞I/O
     慎用異常
     不要重復初始化變量
     盡量指定類的final修飾符
     盡量使用局部變量
     乘法和除法
  二JEE篇
     使用緩沖標記
     始終通過會話Bean訪問實體Bean
     選擇合適的引用機制
     在部署描述器中設置只讀屬性
     緩沖對EJB Home的訪問
     為EJB實現本地接口
     生成主鍵
     及時清除不再需要的會話
     在JSP頁面中關閉無用的會話
     Servlet與內存使用
     HTTP KeepAlive
     JDBC與Unicode
     JDBC與I/O
     內存數據庫
  三GUI篇
     用JAR壓縮類文件
     提示Applet裝入進程
     在畫出圖形之前預先裝入它
     覆蓋update方法
     延遲重畫操作
     使用雙緩沖區
     使用BufferedImage
     使用VolatileImage
     使用Window Blitting
  四補充資料
  ===================================
  正文:
  ===================================
  一通用篇
  
  通用篇討論的問題適合於大多數Java應用
  
   不用new關鍵詞創建類的實例
  
  用new關鍵詞創建類的實例時構造函數鏈中的所有構造函數都會被自動調用但如果一個對象實現了Cloneable接口我們可以調用它的clone()方法clone()方法不會調用任何類構造函數
  在使用設計模式(Design Pattern)的場合如果用Factory模式創建對象則改用clone()方法創建新的對象實例非常簡單例如下面是Factory模式的一個典型實現
  public static Credit getNewCredit() {
  return new Credit();
  }
  改進後的代碼使用clone()方法如下所示
  private static Credit BaseCredit = new Credit();
  public static Credit getNewCredit() {
  return (Credit) BaseCreditclone();
  }
  上面的思路對於數組處理同樣很有用
   使用非阻塞I/O
  版本較低的JDK不支持非阻塞I/O API為避免I/O阻塞一些應用采用了創建大量線程的辦法(在較好的情況下會使用一個緩沖池)這種技術可以在許多必須支持並發I/O流的應用中見到如Web服務器報價和拍賣應用等然而創建Java線程需要相當可觀的開銷
  JDK 引入了非阻塞的I/O庫(javanio)如果應用要求使用版本較早的JDK在這裡有一個支持非阻塞I/O的軟件包
  請參見Sun中國網站的《調整Java的I/O性能》
   慎用異常
  異常對性能不利拋出異常首先要創建一個新的對象Throwable接口的構造函數調用名為fillInStackTrace()的本地(Native)方法fillInStackTrace()方法檢查堆棧收集調用跟蹤信息只要有異常被拋出VM就必須調整調用堆棧因為在處理過程中創建了一個新的對象
  異常只能用於錯誤處理不應該用來控制程序流程
   不要重復初始化變量
  默認情況下調用類的構造函數時 Java會把變量初始化成確定的值所有的對象被設置成null整數變量(byteshortintlong)設置成float和double變量設置成邏輯值設置成false當一個類從另一個類派生時這一點尤其應該注意因為用new關鍵詞創建一個對象時構造函數鏈中的所有構造函數都會被自動調用
   盡量指定類的final修飾符
  帶有final修飾符的類是不可派生的在Java核心API中有許多應用final的例子例如javalangString為String類指定final防止了人們覆蓋length()方法
  另外如果指定一個類為final則該類所有的方法都是finalJava編譯器會尋找機會內聯(inline)所有的final方法(這和具體的編譯器實現有關)此舉能夠使性能平均提高%
   盡量使用局部變量
  調用方法時傳遞的參數以及在調用中創建的臨時變量都保存在棧(Stack)中速度較快其他變量如靜態變量實例變量等都在堆(Heap)中創建速度較慢另外依賴於具體的編譯器/JVM局部變量還可能得到進一步優化請參見《盡可能使用堆棧變量》
   乘法和除法
  考慮下面的代碼
  for (val = ; val < 100000; val +=5) { alterX = val * 8; myResult = val * 2; }
  用移位操作替代乘法操作可以極大地提高性能。tw.WINGWiT.Com下面是修改後的代碼:
  for (val = 0; val < 100000; val += 5) { alterX = val << 3; myResult = val << 1; }
  修改後的代碼不再做乘以8的操作,而是改用等價的左移3位操作,每左移1位相當於乘以2。相應地,右移1位操作相當於除以2。值得一提的是,雖然移位操作速度快,但可能使代碼比較難於理解,所以最好加上一些注釋。
  二、J2EE篇
  前面介紹的改善性能技巧適合於大多數Java應用,接下來要討論的問題適合於使用JSP、EJB或JDBC的應用。
  2.1 使用緩沖標記
  一些應用服務器加入了面向JSP的緩沖標記功能。例如,BEA的WebLogic Server從6.0版本開始支持這個功能,Open Symphony工程也同樣支持這個功能。JSP緩沖標記既能夠緩沖頁面片斷,也能夠緩沖整個頁面。當JSP頁面執行時,如果目標片斷已經在緩沖之中,則生成該片斷的代碼就不用再執行。頁面級緩沖捕獲對指定URL的請求,並緩沖整個結果頁面。對於購物籃、目錄以及門戶網站的主頁來說,這個功能極其有用。對於這類應用,頁面級緩沖能夠保存頁面執行的結果,供後繼請求使用。
  對於代碼邏輯復雜的頁面,利用緩沖標記提高性能的效果比較明顯;反之,效果可能略遜一籌。
  請參見《用緩沖技術提高JSP應用的性能和穩定性》。
  2.2 始終通過會話Bean訪問實體Bean
  直接訪問實體Bean不利於性能。當客戶程序遠程訪問實體Bean時,每一個get方法都是一個遠程調用。訪問實體Bean的會話Bean是本地的,能夠把所有數據組織成一個結構,然後返回它的值。
  用會話Bean封裝對實體Bean的訪問能夠改進事務管理,因為會話Bean只有在到達事務邊界時才會提交。每一個對get方法的直接調用產生一個事務,容器將在每一個實體Bean的事務之後執行一個“裝入-讀取”操作。
  一些時候,使用實體Bean會導致程序性能不佳。如果實體Bean的唯一用途就是提取和更新數據,改成在會話Bean之內利用JDBC訪問數據庫可以得到更好的性能。
  2.3 選擇合適的引用機制
  在典型的JSP應用系統中,頁頭、頁腳部分往往被抽取出來,然後根據需要引入頁頭、頁腳。當前,在JSP頁面中引入外部資源的方法主要有兩種:include指令,以及include動作。
  include指令:例如<%@ include file="l" %>。該指令在編譯時引入指定的資源。在編譯之前,帶有include指令的頁面和指定的資源被合並成一個文件。被引用的外部資源在編譯時就確定,比運行時才確定資源更高效。
  include動作:例如。該動作引入指定頁面執行後生成的結果。由於它在運行時完成,因此對輸出結果的控制更加靈活。但時,只有當被引用的內容頻繁地改變時,或者在對主頁面的請求沒有出現之前,被引用的頁面無法確定時,使用include動作才合算。
  2.4 在部署描述器中設置只讀屬性
  實體Bean的部署描述器允許把所有get方法設置成“只讀”。當某個事務單元的工作只包含執行讀取操作的方法時,設置只讀屬性有利於提高性能,因為容器不必再執行存儲操作。
  2.5 緩沖對EJB Home的訪問
  EJB Home接口通過JNDI名稱查找獲得。這個操作需要相當可觀的開銷。JNDI查找最好放入Servlet的init()方法裡面。如果應用中多處頻繁地出現EJB訪問,最好創建一個EJBHomeCache類。EJBHomeCache類一般應該作為singleton實現。
  2.6 為EJB實現本地接口
  本地接口是EJB 2.0規范新增的內容,它使得Bean能夠避免遠程調用的開銷。請考慮下面的代碼。
  PayBeanHome home = (PayBeanHome) javax.rmi.PortableRemoteObject.narrow
   (ctx.lookup ("PayBeanHome"), PayBeanHome.class);
  PayBean bean = (PayBean) javax.rmi.PortableRemoteObject.narrow
   (home.create(), PayBean.class);
  第一個語句表示我們要尋找Bean的Home接口。這個查找通過JNDI進行,它是一個RMI調用。然後,我們定位遠程對象,返回代理引用,這也是一個RMI調用。第二個語句示范了如何創建一個實例,涉及了創建IIOP請求並在網絡上傳輸請求的stub程序,它也是一個RMI調用。
  要實現本地接口,我們必須作如下修改:
  方法不能再拋出java.rmi.RemoteException異常,包括從RemoteException派生的異常,比如TransactionRequiredException、TransactionRolledBackException和NoSuchObjectException。EJB提供了等價的本地異常,如TransactionRequiredLocalException、TransactionRolledBackLocalException和NoS
From:http://tw.wingwit.com/Article/program/Java/JSP/201311/19488.html
  • 上一篇文章:

  • 下一篇文章:
  • 推薦文章
    Copyright © 2005-2013 電腦知識網 Computer Knowledge   All rights reserved.