Java代碼常見優化方案


Java代碼常見優化方案

 

首先,良好的編碼規范非常重要。在 java 程序中,訪問速度、資源緊張等問題的大部分原因,都是代碼不規范造成的。

 

單例的使用場景

單例模式對於減少資源占用、提高訪問速度等方面有很多好處,但並不是所有場景都適用於單例。

簡單來說,單例主要適用於以下三個方面:

 

    多線程場景,通過線程同步來控制資源的並發訪問。

    多線程場景,控制數據共享,讓多個不相關的進程或線程之間實現通信(通過訪問同一資源來控制)。

    控制實例的產生,單例只實例化一次,以達到節約資源的目的;

 

不可隨意使用靜態變量

當某個對象被定義為 static 變量,那么 GC 通常是不會回收這個對象所占有的內存。

示例如下:

public class A {

    private static B b = new B();

}

此時靜態變量 b 的生命周期與 A 類同步,即如果 A 類不卸載,b 對象會常駐內存,直到程序終止。

 

創建 Java 對象使用注意事項

根據業務使用場景,盡量避免在循環中 new 對象。

 

這是因為系統要花費時間來創建對象,而且還要花時間對這些對象進行管理和垃圾回收。所以在可以控制的范圍內,盡量保證最大限度地重用對象,最好能用基本的數據類型或數組來替代對象。

 

final 修飾符使用注意事項

 

final 修飾符的類是不可派生的,即不可被繼承。在 java 核心代碼中,有很多 被 final 修飾的類,如 java.lang.String 類。

 

如果一個類是 final 的,則該類所有方法都是 final 的。java 編譯器會尋找機會內聯(inline)所有的 final 方法,這與具體的編譯器實現有關。這樣做能夠使性能平均提高 50%

class A {

public void setSize (int size) {

this.size = size;

}

private int size;

}

// setSize 方法變為 final ,性能更好

class A {

final public void setSize (int size) {

this.size = size;

}

private int size;

}

 

 

讓訪問實例變量的 getter/setter 方法變成 final:簡單的 getter/setter 方法應該被置成 final ,這會告訴編譯器此方法不會被重載,可以變成 ”inlined” 。

 

局部變量使用規范

調用方法時傳遞的參數以及在調用中創建的臨時變量都保存在棧(Stack)中,速度較快;其他變量,如靜態變量、實例變量等,都在堆(Heap)中創建,速度較慢。

 

處理好包裝類型和基本類型的使用場所

基本類型:byte,short,int,long,float,double,char,boolean

對應包裝類型:Byte,Short,Int,Long,Float,Double,Character,Boolean

 

基本類型和包裝類型在使用過程中可以相互轉換,但它們所產生的內存區域是完全不同的。基本類型的產生和處理都在棧中處理,包裝類型是引用類型,其對象是在堆中產生實例。

 

在集合類對象,有對象方面需要的處理使用包裝類型合適,其他情況的處理提倡使用基本類型。

 

使用基本數據類型代替對象

String s1 = "hello";

這種方式會創建一個hello” 字符串,而且 JVM 的字符緩存池會緩存這個字符串。

String s2 = new String("hello");

 

 

這種方式除了創建字符串外,s2 所引用的 String 對象底層包含一個 char[] 數組,其中依次存放了 h,e,l,l,o

 

synchronized 使用規范

實現同步需要很大的系統開銷作為代價的,甚至可能造成死鎖。所以盡量避免無謂的同步控制。

synchronize 方法被調用時會直接把當前對象鎖住,在該方法執行完之前其他線程無法調用當前對象的其它方法。比較靈活的用法是使用代碼塊同步代替在方法中同步。

 

finalize使用規范

不要將資源清理放在 finalize 方法中完成,這種方法也很少使用。

由於 GC 的工作量很大,尤其是回收 Young 代內存時,大都會引起應用程序暫停。如果選擇使用 finalize 方法進行資源清理,會導致 GC 負擔加大,程序運行效率變差。

不需要線程同步,應盡量使用 HashMap ArrayList

HashTable Vector 等使用了同步機制,導致降低。

 

HashMap 使用規范

創建一個比較大的 hashMap 時,應該使用帶有參數的構造函數創建對象。

示例如下:

public HashMap(int initialCapacity, float loadFactor);

hash 擴容是一件很耗費性能的事,默認構造函數創建的對象的 initialCapacity 只有 16loadFactor 0.75 ,最好准確的估計所需要的最佳大小。同樣對於 Hashtable Vectors 也是如此。

 

減少對變量的重復計算

for (int i = 0; i < list.size(); i++) {...}

// 應該改為

for (int i=0, l=list.size(); i < l; i++) {...}

 

避免不必要的創建對象

A a = new A();

if (i == 1) {

    list.add(a);

}

// 應該改為

if (i == 1) {

    A a = new A();

    list.add(a);

}

 

finally 使用規范

try-catch 里,使用到的資源要能夠被釋放,以避免資源泄漏,這最好在 finally 塊中去做。無論程序執行是否有異常,finally 里的代碼總是會執行的,這樣可以確保資源的正確關閉。

 

StringBuffer使用規范

StringBuffer 的無參構造函數會創建一個默認 16 的字符數組。在使用過程中,如果數組長度超出 16 ,就要重新分配內存,創建一個容量更大的數組,並將原先的數組復制過來,再丟棄舊的數組。

 

在多數情況下,可以在創建 StringBuffer 的時候指定大小,避免了在容量不夠的時候自動增長,以提高性能。

StringBuffer sb= new StringBuffer(int capacity);

顯式釋放空間讓 gc 回收對象

多數情況下,方法內部的局部引用變量所引用的對象會隨着方法結束而變成垃圾被回收。因此在程序中無需將局部引用變量顯式設為 null

 

示例如下:

void gcTest1() {

    Object obj = new Object();

    ……

    obj = null;

}

 

 

隨着方法 gcTest1() 的執行完成,程序中局部引用變量 obj 的作用域就結束了,這時沒有必要執行 obj = null

 

反例如下:

void gcTest2(){

    Object obj = new Object();

    ……

    obj = null;

    //耗時,耗內存操作

    ……

}

此時需要盡早釋放不再使用的空間,執行 obj = null 顯式釋放局部引用變量 obj

 

二維數組使用規范

二維數據占用的內存空間大概是一維數組的 10 倍以上。

 

split 使用場景

盡量避免使用 split split 使用正則表達式,效率比較低,如果是頻繁的調用將會耗費大量資源。

 

如果確實需要頻繁的調用 split ,使用 apache StringUtils.split(string,char) 較好 ,可以緩存結果。

 

ArrayList LinkedList 使用規范

對於線性表及鏈表,隨機查詢的操作ArrayList 優於 LinkedList LinkedList 需要移動指針。增加刪除的操作 LinkedList 優於 ArrayList ArrayList 需要移動數據。

 

System.arraycopy() 使用規范

盡量使用 System.arraycopy() 復制數組,它要比通過循環來復制數組快的多。

 

緩存對象

將經常使用的對象進行緩存時,可以使用數組或者 HashMap 等容器來緩存。這種方式需要自己管理這些容器,可能導致系統占用過多的緩存,性能下降。

 

也可以使用一些第三方的開源工具,如 EhCache Oscache 進行緩存,他們基本都實現了 FIFO/FLU 等緩存算法。

 

盡量避免非常大的內存分配

有的問題不是由於堆內存不夠造成的,而是因為內存分配失敗造成的。(gc會進行內存碎片整理)

 

如果分配的內存塊都必須是連續的,隨着堆越來越滿,找到較大的連續塊會越來越困難。

 

try/catch 使用場景

不要在循環中使用 try/catch 語句,應該把 try/catch 放在循環最外層。

喜歡這樣文章的可以關注我,我會持續更新,你們的關注是我更新的動力!需要更多java學習資料的也可以私信我!

祝關注我的人都:身體健康,財源廣進,福如東海,壽比南山,早生貴子,從不掉發!


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM