1、關(guān)于J2ME的虛擬機
J2ME虛擬機最嚴重影響程序性能的就是進行垃圾回收操作,一旦進行垃圾回收,程序的主線程一般會暫時掛起,以方便進行垃圾回收操作。在程序上的表現(xiàn)就是程序出現(xiàn)暫時的停頓,這將極大地影響用戶的體驗。因此必須盡量減少垃圾回收進行的次數(shù),近最大努力控制垃圾回收的執(zhí)行,盡量減少垃圾回收執(zhí)行的時間。
J2ME虛擬機中JIT技術(shù)的應用,目前我沒有發(fā)現(xiàn)有顯著的文章來進行描述,由于JIT技術(shù)需要實時編譯并且耗費內(nèi)存較多,因此,我認為MIDP1.0中并沒有采用JIT技術(shù)。而MIDP2.0中有可能采用JIT技術(shù),但是J2ME的JIT技術(shù)與J2SE的性能應該不是一個數(shù)量級上的,由于CPU性能有限,注定無法做復雜的JIT編譯,而且由于JIT耗費內(nèi)存,也注定無法對代碼進行大規(guī)模的JIT編譯。
2、關(guān)于虛擬機
我認為,目前客戶端虛擬機技術(shù),應該說是發(fā)展到一個轉(zhuǎn)折點,未來可能會出現(xiàn)重大的技術(shù)突破。目前無論是Java還是.net基本上采用的都是分代式垃圾回收和分支預測JIT技術(shù)。因此目前這兩個虛擬機的性能相差不是很大,因此對于程序的優(yōu)化,基本上真對這兩種技術(shù)來進行。
關(guān)于分代式垃圾回收
分代式垃圾回收技術(shù)應該是目前客戶端虛擬機垃圾回收技術(shù)的主流,就是說增加對壽命短對象的收集,而減少對長壽命對象的收集。這里使用術(shù)語第一代和第二代的術(shù)語來描述。第一代應當說是程序新分配的內(nèi)存,從統(tǒng)計數(shù)據(jù)來看,對象越年輕,被回收的可能性就越大,因此,對第一代的垃圾回收進行的頻繁一些。而一旦進行了第一代的垃圾回收,未被回收的對象將會成為第二代對象。對于第二代對象的回收,由于它的生命期更長,因此在到達第二代對象空間閾值的時候并不會收集,這樣就減少了回收的次數(shù)。防止垃圾回收帶來的系統(tǒng)停頓。
關(guān)于分支預測
JIT技術(shù)在虛擬機中已經(jīng)被證明能極大地加快程序速度,而目前基本上采用的是帶有分支預測技術(shù)的JIT編譯器,因此越背頻繁執(zhí)行的語句,就越有可能被JIT編譯器編譯,從而加快程序的速度。但是目前的對J2ME虛擬機來說,性能有限,因此JIT的應用的也有限,在程序?qū)懽魃希瑧攷椭M行JIT編譯。
3、J2ME(MIDP)對于這這兩種技術(shù)的優(yōu)化
針對垃圾回收的優(yōu)化
垃圾回收優(yōu)化的核心思想就是減少垃圾回收的次數(shù),增加垃圾回收中資源的回收量。
先說垃圾回收次數(shù)的優(yōu)化,在上文中已經(jīng)說明,分代式垃圾回收,第一代的垃圾回收進行的次數(shù)較頻繁,因此垃圾回收首先針對第一代垃圾回收,就是說應該避免在成員函數(shù)中產(chǎn)生新的對象。
這里在書中有明顯的應用,在滾屏游戲的設計中,需要進行矩形的判斷,這里采用的方式都是定義的到類中的矩形,而不是定義函數(shù)矩形,在碰撞判斷中調(diào)用的矩形都是在類的構(gòu)造函數(shù)中生成的,并不在函數(shù)中生成,由于需要頻繁調(diào)用碰撞檢測,因此如果定義在函數(shù)中將會增加垃圾回收的次數(shù)。具體情況如下:
class Sprite
{
public Rect rect1 = new Rect();
public Rect rect2 = new Rect();
bool checkCollision()
{
//位置判斷后,進行初始化,但是不分配產(chǎn)生新的對象
rect1.x,rect1.y,rect1.dx,ect1.dy
rect2.x,rect2.y,rect2.dx,rect2.dy
}
}
這樣就顯著減少了對象的生成,注意這里還有一個優(yōu)化的地方,基本上每次判斷,dx,dy值是固定的,因此在構(gòu)造函數(shù)中應當初始化dx,dy,這樣將會減少初始化。因此書中的程序中有很多看起來不應當定義為類程序的變量,都被定義為類成員,這極大地減少了垃圾回收的次數(shù)。
而對于二代的垃圾回收,就是在程序中不要隨時把無用的資源置為null,這樣可能會激發(fā)二代回收。
而對于盡可能增加垃圾回收的資源回收量,使調(diào)用顯示垃圾回收,在進行大規(guī)模的資源更換的時候。這個優(yōu)化技術(shù)書中沒有說明,但與程序源代碼中有體現(xiàn)。對于類程序?qū)ο螅灰獰o故置為null,而是在資源更換的時候,一般來說這個時候是更換關(guān)卡的時候,此時應當把上關(guān)卡中不再使用的資源全部置為null,然后顯示調(diào)用垃圾回收。再栽入新的資源,這個時候新的資源能夠順利栽入,舊的資源也能夠順利回收。而由于關(guān)卡切換,進行稍微的等待也是可行的,不會影響用戶體驗。
針對JIT編譯的優(yōu)化
JIT編譯的優(yōu)化就是用戶模擬JIT編譯器來進行程序編譯的優(yōu)化,對于頻繁執(zhí)行的地方,盡量優(yōu)化。對于程序中的分支判斷,要把經(jīng)常調(diào)用的分支寫到判斷前面。而在我前面的文章中提到的關(guān)于成員函數(shù)使用get和set,這個在JIT編譯器中基本上是被優(yōu)化掉的,沒有多少意義。如果不是太頻繁,也不用時全部應用破壞程序結(jié)構(gòu),只把最頻繁的進行優(yōu)化即可。
這里還有一個優(yōu)化的地方,對于特別頻繁的執(zhí)行語句,如下的取得數(shù)據(jù)成員的方式:
a.b,如果是int型,最好使用一個臨時變量
int temp = a.b;
這將減少類程序的取得時間,雖然只有幾個時鐘周期,但是對于特別頻繁的調(diào)用和復雜算法,性能還是有一定的提升。
4、總結(jié)
這里提到的優(yōu)化措施每一處對程序的影響都很小,但是積少成多,水滴石穿,注意的地方多了,就會對程序性能產(chǎn)生影響,并且很多優(yōu)化是全局性的,這在程序的架構(gòu)設計之初就應該考慮好的。