ZhipSoft.com
              冬去春來
                  鄭重聲明:本Blog純屬個人學(xué)習(xí)、工作需要,記錄相關(guān)資料。請不要發(fā)表任何有人身攻擊的言論,謝謝!!www.ZhipSoft.com
          posts - 94,comments - 149,trackbacks - 0

           J2EE中的優(yōu)化方案

          1.使用StringBuffer代替String

          String是用來存儲字符串常量的,如果要執(zhí)行“+”的操作,系統(tǒng)會生成一些臨時的對象,并對這些對象進(jìn)行管理,造成不必要的開銷。

          如果字符串有連接的操作,替代的做法是用StringBuffer類的append方法。

          當(dāng)字符串的大小超過缺省16時,代碼實(shí)現(xiàn)了容量的擴(kuò)充,為了避免對象的重新擴(kuò)展其容量,那么最好用StringBuffer sb=new StringBuffer(30)

          2.優(yōu)化循環(huán)體

          Vector vect = new Vector(1000);
          for( inti=0; i<vect.size(); i++){
           ...
          }

            for循環(huán)部分改寫成:

          int size = vect.size();
          for( int i=0; i>size; i++){
           ...
          }

          如果size=1000,就避免了1000次的size()調(diào)用開銷,避免了重復(fù)調(diào)用.

          3.對象的創(chuàng)建

          盡量少用new來初始化一個類的實(shí)例,當(dāng)一個對象是用new進(jìn)行初始化時,其構(gòu)造函數(shù)鏈的所有構(gòu)造函數(shù)都被調(diào)用到,所以new操作符是很消耗系統(tǒng)資源的,new一個對象耗時往往是局部變量賦值耗時的上千倍。同時,當(dāng)生成對象后,系統(tǒng)還要花時間進(jìn)行垃圾回收和處理。

          當(dāng)new創(chuàng)建對象不可避免時,注意避免多次的使用new初始化一個對象。

          盡量在使用時再創(chuàng)建該對象。

          NewObject object = new NewObject();
          int value;
          if(i>0 )
          {
           value =object.getValue();
          }

            可以修改為:

          int value;
          if(i>0 )
          {
           NewObject object = new NewObject();
           Value =object.getValue();
          }

          4.慎用異常處理

            異常是Java的一種錯誤處理機(jī)制,對程序來說是非常有用的,但是異常對性能不利。拋出異常首先要創(chuàng)建一個新的對象,并進(jìn)行相關(guān)的處理,造成系統(tǒng)的開銷,所以異常應(yīng)該用在錯誤處理的情況,不應(yīng)該用來控制程序流程,流程盡量用while,if等處理。

          在不是很影響代碼健壯性的前提下,可以把幾個try/catch塊合成一個。

          討論:需要處理的異常處理和不需要處理的異常處理在捕捉異常類型上應(yīng)該采取什么策略。

          5.變量的使用

             盡量使用局部變量,調(diào)用方法時傳遞的參數(shù)以及在調(diào)用中創(chuàng)建的臨時變量都保存在棧(Stack) 中,速度較快。其他變量,如靜態(tài)變量、實(shí)例變量等,都在堆(Heap)中創(chuàng)建,速度較慢。

          盡量使用靜態(tài)變量,即加修飾符static,如果類中的變量不會隨他的實(shí)例而變化,就可以定義為靜態(tài)變量,從而使他所有的實(shí)例都共享這個變量。

          (但是靜態(tài)變量不能濫用,如果這個變量用的比較少而聲明成靜態(tài)變量,不僅效率不會提高,還會影響性能)

           

          6.I/O操作

              輸入/輸出(I/O)包括很多方面,我們知道,進(jìn)行I/O操作是很費(fèi)系統(tǒng)資源的。程序中應(yīng)該盡量少用I/O操作。使用時可以注意: . 合理控制輸出函數(shù)System.out.println()對于大多時候是有用的,特別是系統(tǒng)調(diào)試的時候,但也會產(chǎn)生大量的信息出現(xiàn)在控制臺和日志上,同時輸出時,有序列化和同步的過程,造成了開銷。

              特別是在發(fā)行版中,要合理的控制輸出,可以在項(xiàng)目開發(fā)時,設(shè)計(jì)好一個Debug的工具類,在該類中可以實(shí)現(xiàn)輸出開關(guān),輸出的級別,根據(jù)不同的情況進(jìn)行不同的輸出的控制。

              我們在調(diào)試程序的時候,我們喜歡用System.out.println()這樣的打印語句來跟蹤我們的錯誤。但在程序發(fā)布的時候我們卻沒有把這樣的語句都刪除掉,在項(xiàng)目的運(yùn)行中,也會影響效能。

          7.使用緩存

            讀寫內(nèi)存要比讀寫文件要快很多,應(yīng)盡可能使用緩沖。

            盡可能使用帶有Buffer的類代替沒有Buffer的類,如可以用BufferedReader 代替Reader,用BufferedWriter代替Writer來進(jìn)行處理I/O操作。

          同樣可以用BufferedInputStream代替InputStream都可以獲得性能的提高。
           
          8.Servlet的效率問題

            Servlet采用請求——響應(yīng)模式提供Web服務(wù),通過ServletResponse以及ServletRequest這兩個對象來輸出和接收用戶傳遞的參數(shù),在服務(wù)器端處理用戶的請求,根據(jù)請求訪問數(shù)據(jù)庫、訪問別的Servlet方法、調(diào)用EJB等等,然后將處理結(jié)果返回給客戶端。

            ·盡量不使用同步

          Servlet是多線程的,以處理不同的請求,基于前面同步的分析,如果有太多的同步就失去了多線程的優(yōu)勢了。

          同步大多數(shù)使用在一個完整的事務(wù)中,避免事務(wù)中多方操作而引起的數(shù)據(jù)不同步現(xiàn)象。能用邏輯控制的盡量的用邏輯控制。

            ·不用保存太多的信息在HttpSession中

            很多時候,存儲一些對象在HttpSession中是有必要的,可以加快系統(tǒng)的開發(fā),如網(wǎng)上商店系統(tǒng)會把購物車信息保存在該用戶的Session中,但當(dāng)存儲大量的信息或是大的對象在會話中是有害的,特別是當(dāng)系統(tǒng)中用戶的訪問量很大,對內(nèi)存的需求就會很高。

          具體開發(fā)時,在這兩者之間應(yīng)作好權(quán)衡。

          我們在寫web應(yīng)用時,經(jīng)常只需要request的地方而使用了session,這樣會是效率大大的降低的。但是我們用到了session,在項(xiàng)目的開發(fā)中又不能很好的利用session,這樣對效率都是有影響的。比如說,我們把用戶信息放在了session中,但是我們有時候在判斷用戶是否登錄的時候,我們傾向去數(shù)據(jù)庫里查這個是否有這個用戶,又是用了request,但是這樣是沒有必要的,因?yàn)槲覀冎恍枰袛鄐ession就行了。如果并發(fā)數(shù)量比較大的時候,服務(wù)器的負(fù)載就會過重。

            ·清除Session

            通常情況,當(dāng)達(dá)到設(shè)定的超時時間時,同時有些Session沒有了活動,服務(wù)器會釋放這些沒有活動的Session,.. 不過這種情況下,特別是多用戶并訪時,系統(tǒng)內(nèi)存要維護(hù)多個的無效Session。

            當(dāng)用戶退出時,應(yīng)該手動釋放,回收資源,實(shí)現(xiàn)如下:..

          HttpSession theSession = request.getSession();
          // 獲取當(dāng)前Session
          if(theSession != null){
           theSession.invalidate(); // 使該Session失效
          }

          9.數(shù)據(jù)庫的操作

          在J2EE開發(fā)的應(yīng)用系統(tǒng)中,數(shù)據(jù)庫訪問一般是個必備的環(huán)節(jié)。數(shù)據(jù)庫用來存儲業(yè)務(wù)數(shù)據(jù),供應(yīng)用程序訪問。

            在Java技術(shù)的應(yīng)用體系中,應(yīng)用程序是通過JDBC(Java Database Connectivity)實(shí)現(xiàn)的接口來訪問數(shù)據(jù)庫的,JDBC支持“建立連接、SQL語句查詢、處理結(jié)果”等基本功能。在應(yīng)用JDBC接口訪問數(shù)據(jù)庫的過程中,只要根據(jù)規(guī)范來實(shí)現(xiàn),就可以達(dá)到要求的功能。

            但是,有些時候進(jìn)行數(shù)據(jù)查詢的效率著實(shí)讓開發(fā)人員不如所愿,明明根據(jù)規(guī)范編寫的程序,運(yùn)行效果卻很差,造成整個系統(tǒng)的執(zhí)行效率不高。

            ·使用速度快的JDBC驅(qū)動

            JDBC API包括兩種實(shí)現(xiàn)接口形式,一種是純Java實(shí)現(xiàn)的驅(qū)動,一種利用ODBC驅(qū)動和數(shù)據(jù)庫客戶端實(shí)現(xiàn),具體有四種驅(qū)動模式并各有不同的應(yīng)用范圍,針對不同的應(yīng)用開發(fā)要選擇合適的JDBC驅(qū)動,在同一個應(yīng)用系統(tǒng)中,如果選擇不同的JDBC驅(qū)動,在效率上會有差別。

          例如,有一個企業(yè)應(yīng)用系統(tǒng),不要求支持不同廠商的數(shù)據(jù)庫,這時就可以選擇模式4的JDBC驅(qū)動,該驅(qū)動一般由數(shù)據(jù)庫廠商實(shí)現(xiàn)的基于本地協(xié)議的驅(qū)動,直接調(diào)用數(shù)據(jù)庫管理系統(tǒng)使用的協(xié)議,減少了模式3中的中間層。

            ·使用JDBC連接池

            為了提高訪問數(shù)據(jù)庫的性能,我們還可以使用JDBC 2.0的一些規(guī)范和特性,JDBC是占用資源的,在使用數(shù)據(jù)庫連接時可以使用連接池Connection Pooling,避免頻繁打開、關(guān)閉Connection。而我們知道,獲取Connection是比較消耗系統(tǒng)資源的。

            Connection緩沖池是這樣工作的:當(dāng)一個應(yīng)用程序關(guān)閉一個數(shù)據(jù)庫連接時,這個連接并不真正釋放而是被循環(huán)利用,建立連接是消耗較大的操作,循環(huán)利用連接可以顯著的提高性能,因?yàn)榭梢詼p少新連接的建立。

            一個通過DataSource獲取緩沖池獲得連接,并連接到一個CustomerDB數(shù)據(jù)源的代碼演示如下:

          Context ctx = new InitialContext();
          DataSource dataSource = (DataSource) ctx.lookup("jdbc/CustomerDB");
          Connection conn = dataSource.getConnection("password","username");

            ·緩存DataSource

            一個DataSource對象代表一個實(shí)際的數(shù)據(jù)源。這個數(shù)據(jù)源可以是從關(guān)系數(shù)據(jù)庫到表格形式的文件,完全依賴于它是怎樣實(shí)現(xiàn)的,一個數(shù)據(jù)源對象注冊到JNDI名字服務(wù)后,應(yīng)用程序就可以從JNDI服務(wù)器上取得該對象,并使用之和數(shù)據(jù)源建立連接。

            通過上面的例子,我們知道DataSource是從連接池獲得連接的一種方式,通過JNDI方式獲得,是占用資源的。

            為了避免再次的JNDI調(diào)用,可以系統(tǒng)中緩存要使用的DataSource。

            ·關(guān)閉所有使用的資源

            系統(tǒng)一般是并發(fā)的系統(tǒng),在每次申請和使用完資源后,應(yīng)該釋放供別人使用,數(shù)據(jù)庫資源每個模式的含義可以參考SUN JDBC的文檔,不同是比較寶貴的,使用完成后應(yīng)該保證徹底的釋放。

            請看下面的代碼段:

          Connection conn = null;
          Statement stmt = null;
          ResultSet rs = null;
          try {
           DataSource dataSource = getDataSource();
           // 取的DataSource的方法,實(shí)現(xiàn)略。
           conn = datasource.getConnection();
           stmt = conn.createStatement();
           rs = stmt.executeQuery("SELECT * FROM ...");
           ... // 其他處理
           rs.close();
           stmt.close();
           conn.close();
          }catch (SQLException ex) {
           ... // 錯誤處理
          }

            粗看似乎沒有什么問題,也有關(guān)閉相關(guān)如Connection等系統(tǒng)資源的代碼,但當(dāng)出現(xiàn)異常后,關(guān)閉資源的代碼可能并不被執(zhí)行,為保證資源的確實(shí)已被關(guān)閉,應(yīng)該把資源關(guān)閉的代碼放到finally塊:

          Connection conn = null;
          Statement stmt = null;
          ResultSet rs = null;
          try {
           DataSource dataSource = getDataSource();
           // 取的DataSource的方法,實(shí)現(xiàn)略。
           conn = datasource.getConnection();
           stmt = conn.createStatement();
           rs = stmt.executeQuery("SELECT * FROM ...");

           ... // 其他處理
          }catch (SQLException ex) {
           ... // 錯誤處理

          }finally{
           if (rs!=null) {
            try {
             rs.close(); // 關(guān)閉ResultSet}
            catch (SQLException ex) {
             ... // 錯誤處理
            }
           }

           if (stmt!=null){
            try {
             stmt.close(); // 關(guān)閉Statement}
            catch (SQLException ex) {
             ... // 錯誤處理
            }
           }
           if (conn!=null){
            try {
             conn.close(); // 關(guān)閉Connection}
            catch (SQLException ex) {
             ... // 錯誤處理
            }
           }
          }

            ·大型數(shù)據(jù)量處理

            當(dāng)我們在讀取諸如數(shù)據(jù)列表、報表等大量數(shù)據(jù)時,可以發(fā)現(xiàn)使用EJB的方法是非常慢的,這時可以使用直接訪問數(shù)據(jù)庫的方法,用SQL直接存取數(shù)據(jù),從而消除EJB的經(jīng)常開支(例如遠(yuǎn)程方法調(diào)用、事務(wù)管理和數(shù)據(jù)序列化,對象的構(gòu)造等)。

            ·緩存經(jīng)常使用的數(shù)據(jù)

            對于構(gòu)建的業(yè)務(wù)系統(tǒng),如果有些數(shù)據(jù)要經(jīng)常要從數(shù)據(jù)庫中讀取,同時,這些數(shù)據(jù)又不經(jīng)常變化,這些數(shù)據(jù)就可以在系統(tǒng)中緩存起來,使用時直接讀取緩存,而不用頻繁的訪問數(shù)據(jù)庫讀取數(shù)據(jù)。

            緩存工作可以在系統(tǒng)初始化時一次性讀取數(shù)據(jù),特別是一些只讀的數(shù)據(jù),當(dāng)數(shù)據(jù)更新時更新數(shù)據(jù)庫內(nèi)容,同時更新緩存的數(shù)據(jù)值。

          一個例子是,在一套企業(yè)應(yīng)用系統(tǒng)中,企業(yè)的信息數(shù)據(jù)(如企業(yè)的名稱)在多個業(yè)務(wù)應(yīng)用模塊中使用,這時就可以把這些數(shù)據(jù)緩存起來,需要時直接讀取緩存的企業(yè)信息數(shù)據(jù)。

          我們經(jīng)常使用Hibernate這樣的持久數(shù)據(jù)層的框架,就很好的利用了緩存的作用,所以在一定程度上彌補(bǔ)了封裝而帶來的效率丟失問題。但是在使用緩存的時候應(yīng)該注意,因?yàn)樵L問的內(nèi)存數(shù)據(jù)而不是真實(shí)的數(shù)據(jù)庫數(shù)據(jù),所以會出現(xiàn)臟讀的情況。同時也并不是所有的東西都應(yīng)該放在緩存中,不經(jīng)常用到的我們就沒有必要放在緩存中。有時候我們配合xml文件來使用,也不失一種好的方法。

           

          一般意義上說,參與系統(tǒng)運(yùn)行的代碼都會對性能產(chǎn)生影響,實(shí)際應(yīng)用中應(yīng)該養(yǎng)成良好的編程規(guī)范、編寫高質(zhì)量的代碼,當(dāng)系統(tǒng)性能出現(xiàn)問題時,要找到主要影響性能的瓶頸所在,然后集中精力優(yōu)化這些代碼,能達(dá)到事半功倍的效果。

            J2EE性能的優(yōu)化包括很多方面的,要達(dá)到一個性能優(yōu)良的系統(tǒng),除了關(guān)注代碼之外,還應(yīng)該根據(jù)系統(tǒng)實(shí)際的運(yùn)行情況,從服務(wù)器軟硬件環(huán)境、集群技術(shù)、系統(tǒng)構(gòu)架設(shè)計(jì)、系統(tǒng)部署環(huán)境、數(shù)據(jù)結(jié)構(gòu)、算法設(shè)計(jì)等方面綜合考慮。

           



                  本Blog純屬個人學(xué)習(xí)、工作需要,記錄相關(guān)資料。請不要發(fā)表任何有人身攻擊的言論,謝謝! www.zhipsoft.cn
          posted on 2007-06-12 08:49 ZhipSoft 閱讀(611) 評論(0)  編輯  收藏 所屬分類: Java
          主站蜘蛛池模板: 海口市| 观塘区| 乐清市| 长丰县| 乌什县| 常熟市| 永城市| 九龙坡区| 珲春市| 阳新县| 仙桃市| 安吉县| 滨州市| 海门市| 外汇| 白玉县| 平武县| 天镇县| 田阳县| 金湖县| 洛隆县| 微山县| 南皮县| 遂昌县| 田阳县| 三原县| 祁东县| 保山市| 宝坻区| 安吉县| 新安县| 丁青县| 秦安县| 库伦旗| 盘山县| 武清区| 辽阳市| 黄骅市| 贵南县| 喀什市| 衡阳县|