java性能的優(yōu)化_第1頁
java性能的優(yōu)化_第2頁
java性能的優(yōu)化_第3頁
已閱讀5頁,還剩7頁未讀, 繼續(xù)免費閱讀

下載本文檔

版權說明:本文檔由用戶提供并上傳,收益歸屬內容提供方,若內容存在侵權,請進行舉報或認領

文檔簡介

1、Java在九十年代中期出現(xiàn)以后,在贏得贊嘆的同時,也引來了一些批評。贏得的贊嘆主要是Java的跨平臺的操作性,即所謂的”WriteOnce,RunAnywhere”.但由丁Java的性能和運行效率同C相比,仍然有很大的差距,從而引來了很多的批評。對于服務器端的應用程序,由丁不大涉及到界面設計和程序的頻繁重啟,Java的性能問題看似不大明顯,從而一些Java的技術,如JSP,Servlet,EJB等在服務器端編程方面得到了很大的應用,但實際上,Java的性能問題在服務器端依然存在。下面我將分四個方面來討論Java的性能和執(zhí)行效率以及提高Java性能的一些方法。1 關丁性能的基本知識.性能的定義在

2、我們討論怎樣提高Java的性能之前,我們需要明白“性能“的真正含義。我們一般定義如下五個方面作為評判性能的標準。1 )運算的性能-哪一個算法的執(zhí)行性能最好)內存的分配-程序需要分配多少內存,運行時的效率和性能最高。2 )啟動的時間-程序啟動需要多少時間。3 )程序的可伸縮性-程序在用戶負載過重的情況下的表現(xiàn)。5)性能的認識用戶怎樣才能認識到程序的性能。對丁不同的應用程序,對性能的要求也不同。例如,大部分的應用程序在啟動時需要較長的時間,從而對啟動時間的要求有所降低;服務器端的應用程序通常都分配有較大的內存空間,所以對內存的要求也有所降低。但是,這并不是所這兩方面的性能可以被忽略。其次,算法的性

3、能對丁那些把商務邏輯運用到事務性操作的應用程序來講非常重要??偟膩碇v,對應用程序的要求將決定對各個性能的優(yōu)先級。.怎樣才能提高JAVA的性能提高JAVA的性能,一般考慮如下的四個主要方面:(1)程序設計的方法和模式一個良好的設計能提高程序的性能,這一點不僅適用丁JAVA也適用也任何的編程語言。因為它充分利用了各種資源,如內存,CPU高速緩存,對象緩沖池及多線程,從而設計出高性能和可伸縮性強的系統(tǒng)。當然,為了提高程序的性能而改變原來的設計是比較困難的,但是,程序性能的重要性常常要高丁設計上帶來的變化。因此,在編程開始之前就應該有一個好的設計模型和方法。(2) JAVA布署的環(huán)境。JAVA布署的環(huán)

4、境就是指用來解釋和執(zhí)行JAVA字節(jié)碼的技術,一般有如下五種。即解釋指令技術(InterpreterTechnology),及時編譯的技術(JustInTimeCompilierTechnology),適應性優(yōu)化技術(AdaptiveOptimizationTechnology),動態(tài)優(yōu)化,提前編譯為機器碼的技術(DynamicOptimization,AheadOfTimeTechnology)和編譯為機器碼的技術(TranslatorTechnology).這些技術一般都通過優(yōu)化線程模型,調整堆和棧的大小來優(yōu)化JAVA的性能。在考慮提高JAVA勺性能時,首先要找到影響JAVA生能的瓶頸(Bo

5、ttleNecks),在確認了設計的合理性后,應該調整JAVA布署的環(huán)境,通過改變一些參數(shù)來提高JAVA應用程序的性能。具體內容見第二節(jié)。(3) JAVA應用程序的實現(xiàn)當討論應用程序的性能問題時,大多數(shù)的程序員都會考慮程序的代碼,這當然是對的,當更重要的是要找到影響程序性能的瓶頸代碼。為了找到這些瓶頸代碼,我們一般會使用一些輔助的工具,如Jprobe,Optimizit,Vtune以及一些分析的工具如TowerJPerformance等。這些輔助的工具能跟蹤應用程序中執(zhí)行每個函數(shù)或方法所消耗掉的時間,從而改善程序的性能。(4) 硬件和操作系統(tǒng)為了提高JAVA應用程序的性能,而采用跟快的CPUf

6、t更多的內存,并認為這是提高程序性能的唯一方法,但事實并非如此。實踐經驗和事實證明,只有遭到了應用程序性能的瓶頸,從而采取適當?shù)梅椒?,如設計模式,布署的環(huán)境,操作系統(tǒng)的調整,才是最有效的。2 .程序中通常的性能瓶頸。所有的應用程序都存在性能瓶頸,為了提高應用程序的性能,就要盡可能的減少程序的瓶頸。以下是在JAVA程序中經常存在的性能瓶頸。程序甲的挾作文件的試寫齊同俗的榛作狂序等待故寫教據(jù)到阿玲或疑也CPD內存桎序不停的務配,辭森擊掃撮內存異市程序不.斷的處理異審消黑了同步程序等待共享聾溜秋群款勝序不特從數(shù)堤唐中返函姓窸了解了這些瓶頸后,就可以有針對性的減少這些瓶頸,從而提高JAVA應用程序的性

7、能4.提高JAVA程序性能的步驟為了提高JAVA程序的性能,需要遵循如下的六個步驟。a)明確對性能的具體要求在實施一個項目之前,必須要明確該項目對丁程序性能的具體要求,如:這個應用程序要支持5000個并發(fā)的用戶,并且響應時間要在5秒鐘之內。但同時也要明白對丁性能的要求不應該同對程序的其他要求沖突。b)了解當前程序的性能你應該了解你的應用程序的性能同項目所要求性能之間的差距。通常的指標是單位時間內的處理數(shù)和響應時間,有時還會比較CPlffi內存的利用率。c)找到程序的性能瓶頸為了發(fā)現(xiàn)程序中的性能瓶頸,通常會使用一些分析工具,如:TowerJApplicationPerformanceAnalyz

8、er或VTune來察看和分析程序堆棧中各個元素的消耗時間,從而正確的找到并改正引起性能降低的瓶頸代碼,從而提高程序的性能。這些工具還能發(fā)現(xiàn)諸如過多的異常處理,垃圾回收等潛在的問題。d)采取適當?shù)拇胧﹣硖岣咝阅苷业搅艘鸪绦蛐阅芙档偷钠款i代碼后,我們就可以用前面介紹過的提高性能的四個方面,即設計模式,JAVA代碼的實現(xiàn),布署JAVA的環(huán)境和操作系統(tǒng)來提高應用程序的性能。具體內容將在下面的內容中作詳細說明。e)只進行某一方面的修改來提高性能一次只改變可能引起性能降低的某一方面,然后觀察程序的性能是否有所提高,而不應該一次改變多個方面,因為這樣你將不知道到底哪個方面的改變提高了程序的性能,哪個方面沒

9、有,即不能知道程序瓶頸在哪。f)返回到步驟c,繼續(xù)作類似的工作,一直達到要求的性能為止。一. JAVA布署的環(huán)境和編譯技術開發(fā)JAVA&用程序時,首先把JAVA勺源程序編譯為與平臺無關的字節(jié)碼。這些字節(jié)碼就可以被各種基丁JVM的技術所執(zhí)行。這些技術主要分為兩個大類。即基丁解釋的技術和基丁提前編譯為本地碼的技術。其示意圖如下:JavaDevelopmentToolPhtfornIndependentJavaBytecod史JavaVirtual&BuildAheadofIimpCompilersPlatformSpecificDeployableModulelzIJJsAmdsInlerpr&t

10、ersJITSDynamicAdaptiveMix-ModeInterpreters具體可分為如下的五類:a)解釋指令技術其結構圖和執(zhí)行過程如下:Fi昏lherchitecnireJAVA的編譯器首先把JAVA源文件編譯為字節(jié)碼。這些字節(jié)碼對丁JAVA虛擬機(JVM)來講就是機器的指令碼。然后,JAVA的解釋器不斷的循環(huán)取出字節(jié)碼進行解釋并執(zhí)行。這樣做的優(yōu)點是可以實現(xiàn)JAVA語言的跨平臺,同時生成的字節(jié)碼也比較緊湊。JAVA的一些優(yōu)點,如安全性,動態(tài)性都得保持;但缺點是省生成的字節(jié)碼沒有經過什么優(yōu)化,同全部編譯好的本地碼相比,速度比較慢。及時編譯技術(JustInTime)及時編譯技術是為了解

11、決指令解釋技術效率比較低,速度比較慢的情況下提出的,其結構圖如下所示。Eig.2Tliearchincnirc其主要變化是在JAVA程序執(zhí)行之前,乂JIT編譯器把JAVA的字節(jié)碼編譯為機器碼。從而在程序運行時直接執(zhí)行機器碼,而不用對字節(jié)碼進行解釋。同時對代碼也進行了部分的優(yōu)化。這樣做的優(yōu)點是大大提高了JAVA程序的性能。同時,由丁編譯的結果并不在程序運行問保存,因此也節(jié)約了存儲空間了加載程序的時間;缺點是由丁JIT編譯器對所有的代碼都想優(yōu)化,因此也浪費了很多的時間。RM和SU修司都提供了相關的JIT產品。b) 適應性優(yōu)化技術(AdaptiveOptimizationTechnology)同JI

12、T技術相比,適應性優(yōu)化技術并不對所有的字節(jié)碼進行優(yōu)化。它會跟蹤程序運行的成個過程,從而發(fā)現(xiàn)需要優(yōu)化的代碼,對代碼進行動態(tài)的優(yōu)化。對優(yōu)化的代碼,采取80/20的策略。從理論上講,程序運行的時間越長,代碼就越優(yōu)化。其結構圖如下:其優(yōu)點是適應性優(yōu)化技術充分利用了程序執(zhí)行時的信息,發(fā)行程序的性能瓶頸,從而提高程序的性能;其缺點是在進行優(yōu)化時可能會選擇不當,發(fā)而降低了程序的性能。其主要產品乂舊M,SUN的HotSpot.c) 動態(tài)優(yōu)化,提前編譯為機器碼的技術(DynamicOptimization,AheadOfTime)動態(tài)優(yōu)化技術充分利用了JAVA源碼編譯,字節(jié)碼編譯,動態(tài)編譯和靜態(tài)編譯的技術。其輸

13、入時JAVA的原碼或字節(jié)碼,而輸出是經過高度優(yōu)化的可執(zhí)行代碼和個來動態(tài)庫的混合(Window中是DLL文件,UNIX中是共享庫.a.so文件)。其結構如下:JfivnFounrmdesJavabytucuckis-卜Nativecompiler,rteploynientandrnatook|DIXexeAAQTDLLperfoinaricrJrjvnbynxntios*1JETcompilermuve烈elIhil4ewill、VMFi&4Thearchitprtiire其優(yōu)點是能大大提高程序的性能;缺點是破壞了JAVA勺可移植性,也對JAVA的安全帶來了一定的隱患。二. 其主要產品是Towe

14、rJ3.0優(yōu)化JAVA程序設計和編碼,提高JAVA程序性能的一些方法。通過使用一些前面介紹過的輔助性工具來找到程序中的瓶頸,然后就可以對瓶頸部分的代碼進行優(yōu)化。一般有兩種方案:即優(yōu)化代碼或更改設計方法。我們一般會選擇后者,因為不去調用以下代碼要比調用一些優(yōu)化的代碼更能提高程序的性能。而一個設計良好的程序能夠精簡代碼,從而提高性能。下面將提供一些在JAVA程序的設計和編碼中,為了能夠提高JAVA程序的性能,而經常采用的一些方法和技巧。1.對象的生成和大小的調整。JAVA程序設計中一個普遍的問題就是沒有好好的利用JAVA語言本身提供的函數(shù),從而常常會生成大量的對象(或實例)。由丁系統(tǒng)不僅要花時間生

15、成對象,以后可能還需花時間對這些對象進行垃圾回收和處理。因此,生成過多的對象將會給程序的性能帶來很大的影響。例1:關于String,StringBuffer,+和appendJAVA語言提供了對丁String類型變量的操作。但如果使用不當,會給程序的性能帶來影響。如下面的語句:Stringname=newString(“HuangWeiFeng);System.out.println(name+ismyname);看似已經很精簡了,其實并非如此。為了生成二進制的代碼,要進行如下的步驟和操作。(1) 生成新的字符申newString(STR_1);復制該字符申。(2) 加載字符申常量”Huang

16、WeiFeng(STR_2);調用字符申的構架器(Constructor);保存該字符申到數(shù)組中(從位置0開始)從java.io.PrintStream類中得到靜態(tài)的out變量生成新的字符申緩沖變量newStringBuffer(STR_BUF_1);復制該字符申緩沖變量調用字符申緩沖的構架器(Constructor);保存該字符申緩沖到數(shù)組中(從位置1開始)(3) 以STR_1為參數(shù),調用字符申緩沖(StringBuffer)類中的append方法。(4) 加載字符申常量”ismyname(STR_3);(5) 以STR_叫參數(shù),調用字符申緩沖(StringBuffer)類中的append方

17、法。(6) 對于STR_BUF_執(zhí)行toString命令。(7) 調用out變量中的println方法,輸出結果。由此可以看出,這兩行簡單的代碼,就生成了STR_1,STR_2,STR_3,STR_4和STR_BUF_五個對象變量。這些生成的類的實例一般都存慶在堆市。堆項對所有類的2類,類的實例進行初始化,同時還要調用類極其每個超類的構架器。而這些操作都是非常消耗系統(tǒng)資源的。因此,對對象的生成進行限制,是完全有必要的。經修改,上面的代碼可以用如下的代碼來替換。StringBuffername=newStringBuffer(“HuangWeiFeng);System.out.println(n

18、ame.append(“ismyname.”).toString();系統(tǒng)將進行如下的操作。生成新的字符申緩沖變量newStringBuffer(STR_BUF_1);復制該字符申緩沖變量加載字符申常量”HuangWeiFeng(STR_1);調用字符申緩沖的構架器(Constructor);保存該字符申緩沖到數(shù)組中(從位置1開始)從java.io.PrintStream類中得到靜態(tài)的out變量加載STR_BUF_1;加載字符申常量”ismyname”(STR_2);以STR_2為參數(shù),調用字符申緩沖(StringBuffer)實例中的append方法。(8) 對于STR_BUF_執(zhí)行toSt

19、ring命令。(STR_3)調用out變量中的println方法,輸出結果。由此可以看出,經過改進后的代碼只生成了四個對象變量:STR_1,STR_2,STR_3和STR_BUF_1f爾可能覺得少生成一個對象不會對程序的性能有很大而提高。但下面的在碼段2的執(zhí)行速度將是代碼段1的2倍。因為代碼段1生成了八個對象,而代碼段2只生成了四個對象。代碼段1:Stringname=newStringBuffer(“HuangWeiFeng);name+=ismy;name+=name;代碼段2:StringBuffername=newStringBuffer(“HuangWeiFeng);name.app

20、end(“ismy”);name.append(“name.”).toString();(1) 因此,充分的利用JAVA提供的庫函數(shù)來優(yōu)化程序,對提高JAVA程序的性能時非常重要的.其注意點主要有如下幾方面;盡可能的使用靜態(tài)變量(StaticClassVariables)如果類中的變量不會隨他的實例而變化,就可以定義為靜態(tài)變量,從而使他所有的實例都共享這個變量。例:publicclassfoo(SomeObjectso=newSomeObject();就可以定義為:(2) publicclassfoo(staticSomeObjectso=newSomeObject();不要對已生成的對象作過

21、多的改變。對于一些類(如:String類)來講,寧愿在重新生成一個新的對象實例,而不應該修改已經生成的對象實例。例:Stringname=”Huang;nameWei”;name=Feng;上述代碼生成了三個String類型的對象實例。而前兩個馬上就需要系統(tǒng)進行垃圾回收處理。如果要對字符申進行連接的操作,性能將得更差。因為系統(tǒng)將不得為此生成更多得臨時變量。如上例1所示。(3) 生成對象時,要分配給它合理的空間和大小JAVA中的很多類都有它的默認的空間分配大小。對于StringBuffer類來講,默認的分配空間大小是16個字符。如果在程序中使用StringBuffer的空間大小不是16個字符,那

22、么就必須進行正確的初始化。(4) 避免生成不太使用或生命周期短的對象或變量。對于這種情況,因該定義一個對象緩沖池。以為管理一個對象緩沖池的開銷要比頻繁的生成和回收對象的開銷小的多。(5) 只在對象作用范圍內進行初始化。JAVA允許在代碼的任何地方定義和初始化對象。這樣,就可以只在對象作用的范圍內進行初始化。從而節(jié)約系統(tǒng)的開銷。例:SomeObjectso=newSomeObject();If(x=1)thenFoo=so.getXX();可以修改為:if(x=1)thenSomeObjectso=newSomeObject();Foo=so.getXX();2.異常(Exceptions)JA

23、VA語言中提供了try/catch來發(fā)方便用戶捕捉異常,進行異常的處理。但是如果使用不當,也會給JAVA程序的性能帶來影響。因此,要注意以下兩點。(1) 避免對應用程序的邏輯使用try/catch如果可以用if,while等邏輯語句來處理,那么就盡可能的不用try/catch語句重用異常在必須要進行異常的處理時,要盡可能的重用已經存在的異常對象。以為在異常的處理中,生成一個異常對象要消耗掉大部分的時間。3.線程(Threading)一個高性能的應用程序中一般都會用到線程。因為線程能充分利用系統(tǒng)的資源。在其他線程因為等待硬盤或網絡讀寫而時,程序能繼續(xù)處理和運行。但是對線程運用不當,也會影響程序的

24、性能。例2:正確使用Vector類Vector主要用來保存各種類型的對象(包括相同類型和不同類型的對象)。但是在一些情況下使用會給程序帶來性能上的影響。這主要是由Vector類的兩個特點所決定的。第一,Vector提供了線程的安全保護功能。即使Vector類中的許多方法同步。但是如果你已經確認你的應用程序是單線程,這些方法的同步就完全不必要了。第二,在Vector查我存儲的各種對象時、常常要花很多的時間進行類型的匹配。而當這些對象都是同一類型時,這些匹配就完全不必要了。因此,有必要設計一個單線程的,保存特定類型對象的類或集合來替代Vector類.用來替換的程序如下(StringVector.j

25、ava):publicclassStringVectorprivateStringdata;privateintcount;publicStringVector()this(10);/defaultsizeis10publicStringVector(intinitialSize)data=newStringinitialSize;publicvoidadd(Stringstr)/ignorenullstringsif(str=null)(return;ensureCapacity(count+1);datacount+=str;privatevoidensureCapacity(intmin

26、Capacity)(intoldCapacity=data.length;if(minCapacityoldCapacity)(StringoldData=data;intnewCapacity=oldCapacity*2;data=newStringnewCapacity;System.arraycopy(oldData,0,data,0,count);publicvoidremove(Stringstr)(if(str=null)(return/ignorenullstrfor(inti=0;icount;i+)(/checkforamatchif(datai.equals(str)(Sy

27、stem.arraycopy(data,i+1,data,i,count-1);/copydata/allowpreviouslyvalidarrayelementbegcddata-count=null;return;publicfinalStringgetStringAt(intindex)if(indexcount)returnnull;/indexis#stringselsereturndataindex;/indexisgood/*/*StringVector.java*因此,代碼:VectorStrings=newVector();Strings.add(“One);Strings

28、.add(“Tw6);StringSecond=(String)Strings.elementAt(1);可以用如下的代碼替換:StringVectorStrings=newStringVector();Strings.add(“On);Strings.add(“Tw6);StringSecond=Strings.getStringAt(1);這樣就可以通過優(yōu)化線程來提高JAVA程序的性能。用于測試的程序如下(TestCollection.java):importjava.util.Vector;publicclassTestCollectionpublicstaticvoidmain(Str

29、ingargs)TestCollectioncollect=newTestCollection();if(args.length=0)System.out.println(Usage:javaTestCollectionvector|stringvector);System.exit(1);if(args0.equals(vector)Vectorstore=newVector();longstart=System.currentTimeMillis();for(inti=0;i1000000;i+)store.addElement(string);longfinish=System.curr

30、entTimeMillis();System.out.println(finish-start);start=System.currentTimeMillis();for(inti=0;i1000000;i+)Stringresult=(String)store.elementAt(i);finish=System.currentTimeMillis();System.out.println(finish-start);elseif(args0.equals(stringvector)StringVectorstore=newStringVector();longstart=System.cu

31、rrentTimeMillis();for(inti=0;i1000000;i+)store.add(string);longfinish=System.currentTimeMillis();System.out.println(finish-start);start=System.currentTimeMillis();for(inti=0;i1000000;i+)Stringresult=store.getStringAt(i);finish=System.currentTimeMillis();System.out.println(finish-start);*/*TestCollec

32、tion.java測試的結果如下(假設標準的時間為1,越小性能越好):剖試的維果如下(恨彼桿璋飽時間方1,建,1、枚能越好上操作addSetfector翼11StringVctor矣0.7QJ5關丁線程的操作,要注意如下幾個方面。(1) 防止過多的同步如上所示,不必要的同步常常會造成程序性能的下降。因此,如果程序是單線程,則一定不要使用同步。同步方法而不要同步整個代碼段對某個方法或函數(shù)進行同步比對整個代碼段進行同步的性能要好。(2) 對每個對象使用多”鎖”的機制來增大并發(fā)。一般每個對象都只有一個”鎖”,這就表明如果兩個線程執(zhí)行一個對象的兩個不同的同步方法時,會發(fā)生”死鎖”。即使這兩個方法并不共享任何資源為了避免這個問題,可以對一個對象實行”多鎖”的機制。如下所示:classfooprivatestaticintvar1;

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網頁內容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
  • 4. 未經權益所有人同意不得將文件中的內容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網僅提供信息存儲空間,僅對用戶上傳內容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內容本身不做任何修改或編輯,并不能對任何下載內容負責。
  • 6. 下載文件中如有侵權或不適當內容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論