JavaGis

          JavaGis大草原

           

          Java性能優(yōu)化技巧J2EE篇(轉(zhuǎn)載)

          J2EE篇

          ????前面介紹的改善性能技巧適合于大多數(shù)Java應(yīng)用,接下來要討論的問題適合于使用JSP、EJB或JDBC的應(yīng)用。

          ????2.1 使用緩沖標(biāo)記

          ????一些應(yīng)用服務(wù)器加入了面向JSP的緩沖標(biāo)記功能。例如,BEA的WebLogic Server從6.0版本開始支持這個功能,Open Symphony工程也同樣支持這個功能。JSP緩沖標(biāo)記既能夠緩沖頁面片斷,也能夠緩沖整個頁面。當(dāng)JSP頁面執(zhí)行時,如果目標(biāo)片斷已經(jīng)在緩沖之中,則生成該片斷的代碼就不用再執(zhí)行。頁面級緩沖捕獲對指定URL的請求,并緩沖整個結(jié)果頁面。對于購物籃、目錄以及門戶網(wǎng)站的主頁來說,這個功能極其有用。對于這類應(yīng)用,頁面級緩沖能夠保存頁面執(zhí)行的結(jié)果,供后繼請求使用。

          ????對于代碼邏輯復(fù)雜的頁面,利用緩沖標(biāo)記提高性能的效果比較明顯;反之,效果可能略遜一籌。

          ????2.2 始終通過會話Bean訪問實體Bean

          ????直接訪問實體Bean不利于性能。當(dāng)客戶程序遠(yuǎn)程訪問實體Bean時,每一個get方法都是一個遠(yuǎn)程調(diào)用。訪問實體Bean的會話Bean是本地的,能夠把所有數(shù)據(jù)組織成一個結(jié)構(gòu),然后返回它的值。

          ????用會話Bean封裝對實體Bean的訪問能夠改進(jìn)事務(wù)管理,因為會話Bean只有在到達(dá)事務(wù)邊界時才會提交。每一個對get方法的直接調(diào)用產(chǎn)生一個事務(wù),容器將在每一個實體Bean的事務(wù)之后執(zhí)行一個“裝入-讀取”操作。

          ????一些時候,使用實體Bean會導(dǎo)致程序性能不佳。如果實體Bean的惟一用途就是提取和更新數(shù)據(jù),改成在會話Bean之內(nèi)利用JDBC訪問數(shù)據(jù)庫可以得到更好的性能。

          ????2.3 選擇合適的引用機(jī)制

          ????在典型的JSP應(yīng)用系統(tǒng)中,頁頭、頁腳部分往往被抽取出來,然后根據(jù)需要引入頁頭、頁腳。當(dāng)前,在JSP頁面中引入外部資源的方法主要有兩種:include指令,以及include動作。

          • include指令:例如<%@ include file="copyright.html" %>。該指令在編譯時引入指定的資源。在編譯之前,帶有include指令的頁面和指定的資源被合并成一個文件。被引用的外部資源在編譯時就確定,比運行時才確定資源更高效。
          • include動作:例如<jsp:include page="copyright.jsp" />。該動作引入指定頁面執(zhí)行后生成的結(jié)果。由于它在運行時完成,因此對輸出結(jié)果的控制更加靈活。但時,只有當(dāng)被引用的內(nèi)容頻繁地改變時,或者在對主頁面的請求沒有出現(xiàn)之前,被引用的頁面無法確定時,使用include動作才合算。

          ????2.4 在部署描述器中設(shè)置只讀屬性

          ????實體Bean的部署描述器允許把所有g(shù)et方法設(shè)置成“只讀”。當(dāng)某個事務(wù)單元的工作只包含執(zhí)行讀取操作的方法時,設(shè)置只讀屬性有利于提高性能,因為容器不必再執(zhí)行存儲操作。

          ????2.5 緩沖對EJB Home的訪問

          ????EJB Home接口通過JNDI名稱查找獲得。這個操作需要相當(dāng)可觀的開銷。JNDI查找最好放入Servlet的init()方法里面。如果應(yīng)用中多處頻繁地出現(xiàn)EJB訪問,最好創(chuàng)建一個EJBHomeCache類。EJBHomeCache類一般應(yīng)該作為singleton實現(xiàn)。

          ????2.6 為EJB實現(xiàn)本地接口

          ????本地接口是EJB 2.0規(guī)范新增的內(nèi)容,它使得Bean能夠避免遠(yuǎn)程調(diào)用的開銷。請考慮下面的代碼。

          ????

          																


          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進(jìn)行,它是一個RMI調(diào)用。然后,我們定位遠(yuǎn)程對象,返回代理引用,這也是一個RMI調(diào)用。第二個語句示范了如何創(chuàng)建一個實例,涉及了創(chuàng)建IIOP請求并在網(wǎng)絡(luò)上傳輸請求的stub程序,它也是一個RMI調(diào)用。

          ????要實現(xiàn)本地接口,我們必須作如下修改:

          • 方法不能再拋出java.rmi.RemoteException異常,包括從RemoteException派生的異常,比如TransactionRequiredException、TransactionRolledBackException和NoSuchObjectException。EJB提供了等價的本地異常,如TransactionRequiredLocalException、TransactionRolledBackLocalException和NoSuchObjectLocalException。
          • 所有數(shù)據(jù)和返回值都通過引用的方式傳遞,而不是傳遞值。
          • 本地接口必須在EJB部署的機(jī)器上使用。簡而言之,客戶程序和提供服務(wù)的組件必須在同一個JVM上運行。
          • 如果Bean實現(xiàn)了本地接口,則其引用不可串行化。

          ????2.7 生成主鍵

          ????在EJB之內(nèi)生成主鍵有許多途徑,下面分析了幾種常見的辦法以及它們的特點。

          ????利用數(shù)據(jù)庫內(nèi)建的標(biāo)識機(jī)制(SQL Server的IDENTITY或Oracle的SEQUENCE)。這種方法的缺點是EJB可移植性差。

          ????由實體Bean自己計算主鍵值(比如做增量操作)。它的缺點是要求事務(wù)可串行化,而且速度也較慢。

          ????利用NTP之類的時鐘服務(wù)。這要求有面向特定平臺的本地代碼,從而把Bean固定到了特定的OS之上。另外,它還導(dǎo)致了這樣一種可能,即在多CPU的服務(wù)器上,同一個毫秒之內(nèi)生成了兩個主鍵。

          ????借鑒Microsoft的思路,在Bean中創(chuàng)建一個GUID。然而,如果不求助于JNI,Java不能確定網(wǎng)卡的MAC地址;如果使用JNI,則程序就要依賴于特定的OS。

          ????還有其他幾種辦法,但這些辦法同樣都有各自的局限。似乎只有一個答案比較理想:結(jié)合運用RMI和JNDI。先通過RMI注冊把RMI遠(yuǎn)程對象綁定到JNDI樹??蛻舫绦蛲ㄟ^JNDI進(jìn)行查找。下面是一個例子:

          ????

          																


          public class keyGenerator extends UnicastRemoteObject implements Remote {
          private static long KeyValue = System.currentTimeMillis();
          public static synchronized long getKey() throws RemoteException { return KeyValue++; }



          ????2.8 及時清除不再需要的會話

          ????為了清除不再活動的會話,許多應(yīng)用服務(wù)器都有默認(rèn)的會話超時時間,一般為30分鐘。當(dāng)應(yīng)用服務(wù)器需要保存更多會話時,如果內(nèi)存容量不足,操作系統(tǒng)會把部分內(nèi)存數(shù)據(jù)轉(zhuǎn)移到磁盤,應(yīng)用服務(wù)器也可能根據(jù)“最近最頻繁使用”(Most Recently Used)算法把部分不活躍的會話轉(zhuǎn)儲到磁盤,甚至可能拋出“內(nèi)存不足”異常。在大規(guī)模系統(tǒng)中,串行化會話的代價是很昂貴的。當(dāng)會話不再需要時,應(yīng)當(dāng)及時調(diào)用HttpSession.invalidate()方法清除會話。HttpSession.invalidate()方法通??梢栽趹?yīng)用的退出頁面調(diào)用。

          ????2.9 在JSP頁面中關(guān)閉無用的會話

          ????對于那些無需跟蹤會話狀態(tài)的頁面,關(guān)閉自動創(chuàng)建的會話可以節(jié)省一些資源。使用如下page指令:

          ????

          																


          <%@ page session="false"%>




          ????2.10 Servlet與內(nèi)存使用

          ????許多開發(fā)者隨意地把大量信息保存到用戶會話之中。一些時候,保存在會話中的對象沒有及時地被垃圾回收機(jī)制回收。從性能上看,典型的癥狀是用戶感到系統(tǒng)周期性地變慢,卻又不能把原因歸于任何一個具體的組件。如果監(jiān)視JVM的堆空間,它的表現(xiàn)是內(nèi)存占用不正常地大起大落。

          ????解決這類內(nèi)存問題主要有二種辦法。第一種辦法是,在所有作用范圍為會話的Bean中實現(xiàn)HttpSessionBindingListener接口。這樣,只要實現(xiàn)valueUnbound()方法,就可以顯式地釋放Bean使用的資源。

          ????另外一種辦法就是盡快地把會話作廢。大多數(shù)應(yīng)用服務(wù)器都有設(shè)置會話作廢間隔時間的選項。另外,也可以用編程的方式調(diào)用會話的setMaxInactiveInterval()方法,該方法用來設(shè)定在作廢會話之前,Servlet容器允許的客戶請求的最大間隔時間,以秒計。

          ????2.11 HTTP Keep-Alive

          ????Keep-Alive功能使客戶端到服務(wù)器端的連接持續(xù)有效,當(dāng)出現(xiàn)對服務(wù)器的后繼請求時,Keep-Alive功能避免了建立或者重新建立連接。市場上的大部分Web服務(wù)器,包括iPlanet、IIS和Apache,都支持HTTP Keep-Alive。對于提供靜態(tài)內(nèi)容的網(wǎng)站來說,這個功能通常很有用。但是,對于負(fù)擔(dān)較重的網(wǎng)站來說,這里存在另外一個問題:雖然為客戶保留打開的連接有一定的好處,但它同樣影響了性能,因為在處理暫停期間,本來可以釋放的資源仍舊被占用。當(dāng)Web服務(wù)器和應(yīng)用服務(wù)器在同一臺機(jī)器上運行時,Keep-Alive功能對資源利用的影響尤其突出。

          ????2.12 JDBC與Unicode

          ????想必你已經(jīng)了解一些使用JDBC時提高性能的措施,比如利用連接池、正確地選擇存儲過程和直接執(zhí)行的SQL、從結(jié)果集刪除多余的列、預(yù)先編譯SQL語句,等等。

          ????除了這些顯而易見的選擇之外,另一個提高性能的好選擇可能就是把所有的字符數(shù)據(jù)都保存為Unicode(代碼頁13488)。Java以Unicode形式處理所有數(shù)據(jù),因此,數(shù)據(jù)庫驅(qū)動程序不必再執(zhí)行轉(zhuǎn)換過程。但應(yīng)該記?。喝绻捎眠@種方式,數(shù)據(jù)庫會變得更大,因為每個Unicode字符需要2個字節(jié)存儲空間。另外,如果有其他非Unicode的程序訪問數(shù)據(jù)庫,性能問題仍舊會出現(xiàn),因為這時數(shù)據(jù)庫驅(qū)動程序仍舊必須執(zhí)行轉(zhuǎn)換過程。

          ????2.13 JDBC與I/O

          ????如果應(yīng)用程序需要訪問一個規(guī)模很大的數(shù)據(jù)集,則應(yīng)當(dāng)考慮使用塊提取方式。默認(rèn)情況下,JDBC每次提取32行數(shù)據(jù)。舉例來說,假設(shè)我們要遍歷一個5000行的記錄集,JDBC必須調(diào)用數(shù)據(jù)庫157次才能提取到全部數(shù)據(jù)。如果把塊大小改成512,則調(diào)用數(shù)據(jù)庫的次數(shù)將減少到10次。

          ????在一些情形下這種技術(shù)無效。例如,如果使用可滾動的記錄集,或者在查詢中指定了FOR UPDATE,則塊操作方式不再有效。

          ????2.14 內(nèi)存數(shù)據(jù)庫

          ????許多應(yīng)用需要以用戶為單位在會話對象中保存相當(dāng)數(shù)量的數(shù)據(jù),典型的應(yīng)用如購物籃和目錄等。由于這類數(shù)據(jù)可以按照行/列的形式組織,因此,許多應(yīng)用創(chuàng)建了龐大的Vector或HashMap。在會話中保存這類數(shù)據(jù)極大地限制了應(yīng)用的可伸縮性,因為服務(wù)器擁有的內(nèi)存至少必須達(dá)到每個會話占用的內(nèi)存數(shù)量乘以并發(fā)用戶最大數(shù)量,它不僅使服務(wù)器價格昂貴,而且垃圾收集的時間間隔也可能延長到難以忍受的程度。

          ????一些人把購物籃/目錄功能轉(zhuǎn)移到數(shù)據(jù)庫層,在一定程度上提高了可伸縮性。然而,把這部分功能放到數(shù)據(jù)庫層也存在問題,且問題的根源與大多數(shù)關(guān)系數(shù)據(jù)庫系統(tǒng)的體系結(jié)構(gòu)有關(guān)。對于關(guān)系數(shù)據(jù)庫來說,運行時的重要原則之一是確保所有的寫入操作穩(wěn)定、可靠,因而,所有的性能問題都與物理上把數(shù)據(jù)寫入磁盤的能力有關(guān)。關(guān)系數(shù)據(jù)庫力圖減少I/O操作,特別是對于讀操作,但實現(xiàn)該目標(biāo)的主要途徑只是執(zhí)行一套實現(xiàn)緩沖機(jī)制的復(fù)雜算法,而這正是數(shù)據(jù)庫層第一號性能瓶頸通常總是CPU的主要原因。

          ????一種替代傳統(tǒng)關(guān)系數(shù)據(jù)庫的方案是,使用在內(nèi)存中運行的數(shù)據(jù)庫(In-memory Database),例如TimesTen。內(nèi)存數(shù)據(jù)庫的出發(fā)點是允許數(shù)據(jù)臨時地寫入,但這些數(shù)據(jù)不必永久地保存到磁盤上,所有的操作都在內(nèi)存中進(jìn)行。這樣,內(nèi)存數(shù)據(jù)庫不需要復(fù)雜的算法來減少I/O操作,而且可以采用比較簡單的加鎖機(jī)制,因而速度很快。

          posted on 2006-09-02 14:25 zdygis 閱讀(191) 評論(0)  編輯  收藏 所屬分類: Java

          導(dǎo)航

          統(tǒng)計

          常用鏈接

          留言簿(1)

          隨筆分類

          隨筆檔案

          文章分類

          文章檔案

          Gis世界

          Java天空

          Oracle海洋

          搜索

          最新評論

          閱讀排行榜

          評論排行榜

          主站蜘蛛池模板: 博客| 固阳县| 县级市| 周宁县| 塔河县| 苏尼特左旗| 南京市| 西和县| 嵊州市| 子洲县| 玛多县| 富川| 东丽区| 峨山| 屯门区| 棋牌| 新河县| 阜平县| 通道| 织金县| 榕江县| 中方县| 沁水县| 民乐县| 班戈县| 吉首市| 宣武区| 弥勒县| 泰顺县| 喜德县| 正镶白旗| 息烽县| 古交市| 牟定县| 松桃| 凤城市| 新安县| 洪雅县| 轮台县| 伊宁市| 行唐县|