3.1 對象創建
對象的創建是一個非常昂貴的工作,而由于對象的創建而導致經常性的垃圾收集則是一個更加消耗時間和CPU的操作。我們在編碼時,應當盡量的減少對象的創建。不要在經常被執行的代碼中創建對象;使用集合對象時最好預先分配其大小;當一個class的多個實例都需要獲取某個對象時,最好能標記那個對象static;當不需要stack trace時盡可能的重用異常實例等等都能很有效的避免對象創建而導致的額外的開銷。下面是一些常用的有效的策略:
1) 對象池技術
在Java中開發一個普遍性的對象池架構可以更好地利用資源,并可以使對象創建的成本降到最小。大多數人對直接或間接運用對象池來連接一個數據庫都很熟悉。但通常你也可以將對象放入對象池中從而節省重要的資源、提高程序的效率并控制對不充足資源的訪問。出于對設計、成本或性能的考慮,放入對象池中的對象通常是有限的。它們或者是初始化成本很高的對象,或者是很少用的對象。運用對象池我們可以管理競爭性客戶端對有限的對象集的訪問。
對象池主要是可以更好地運用你的資源。例如,設想有相當多的客戶要有效運用很少的數據庫連接或網絡連接。通過限制對對象的訪問(只在客戶端需要的時候才能訪問對象),你就可以釋放資源,讓其它客戶端使用。通過對象池提高對象的利用率通常可以提高系統的性能。
你可以使用對象池使初始化的成本達到最小。典型的例子包括數據庫、網絡連接和線程。這樣的連接通常需要很多時間來初始化。一旦創建了這些連接,你就可以重用它們,從而極大地節省了成本。因此,你可以將初始化成本很高(從時間、內存或其它資源方面考慮)的對象放入對象池中。例如,大多數容器都將EJB放入對象池中,從而避免重復的資源分配和狀態初始化。
一個設計良好的對象池架構具有普遍性,它適合不同應用程序的需要。可以讓你控制對象池的容量、對象填充策略和對象狀態。它可以極大地提高你的應用程序的效率,不管從速度方面考慮,還是從資源利用率方面考慮,該架構都可以提供這樣的好處。
在這里,給大家推薦一個開源的項目Commons-Pool(http://jakarta.apache.org/commons/pool/),我還沒來得及研究,誰用過了,感覺好的,麻煩告訴我一下,謝謝!
2) ThreadLocal技術
使用此技術獲取線程綁定的帶狀態的單例對象。
3) 單例模式
通過單例模式或使定義對象static來使得對象的實例只能有一個并被其他對象所共享。
4) 枚舉常量
使用整數取代字符串作為枚舉常量,比如FEMALE和MALE我們可以用整數1和2來替代。這樣將帶來速度上和內存上的優勢。
5) 使用SoftReference,WeakReference和PhantomReference引用類
引用類的主要功能就是能夠引用仍可以被垃圾收集器回收的對象。在引入引用類之前,我們只能使用強引用(Strong Reference)。例如obj這個引用將引用堆中存儲的一個對象,只要obj引用還存在,垃圾收集器就永遠不會釋放用來容納該對象的存儲空間。當obj超出范圍或被顯式指定為null時,垃圾收集器就認為沒有對這個對象的其他引用,也就可以收集它了。然而還需要注意一個重要的細節:僅憑對象可以被收集并不意味著垃圾收集器的一次指定運行就能夠回收它。由于各種垃圾收集算法不同,某些算法會更頻繁地分析生存期較短的對象,而不是較老、生存期較長的對象。因此,一個可供收集的對象可能永遠也不會被回收。如果程序在垃圾收集器釋放對象之前結束,這種情況就可能會出現。因此,概括地說,你永遠無法保證可供收集的對象總是會被垃圾收集器收集。
讓我們來看看一些術語和定義:
強可及對象(Strongly Reachable):可以通過強引用訪問的對象。
軟可及對象(Softly Reachable):不是強可及對象,并且能夠通過軟引用訪問的對象。
弱可及對象(Weakly Reachable):不是強可及對象也不是軟可及對象,并且能夠通過弱引用訪問的對象。
虛可及對象(Phantomly Reachable):不是強可及對象、軟可及對象,也不是弱可及對象,已經結束的,可以通過虛引用訪問的對象。
清除:將引用對象的refernce域設置為null,并將引用類在堆中引用的對象聲明為可結束的。
SoftReference類:SoftReference類的一個典型用途就是用于內存敏感的高速緩存。SoftReference的原理是:在保持對對象的引用時保證在JVM報告內存不足情況之前清楚所有的軟引用。關鍵之處在于,垃圾收集器在運行時可能會(也可能不會)釋放軟可及對象。對象是否被是否取決于垃圾收集器的算法以及垃圾收集器運行時可用的內存數量。
WeakReference類:WeakReference類的一個典型用途就是規范化映射(Canonicalized Mapping)。另外,對于那些生存期相對較長而且重新創建的開銷也不高的對象來說,弱引用也比較有用。關鍵之處在于,垃圾收集器運行時如果碰到了弱可及對象,將釋放 WeakReference 引用的對象。然而,請注意,垃圾收集器可能要運行多次才能找到并釋放弱可及對象。
PhantomReference類:PhantomReference 類只能用于跟蹤對被引用對象即將進行的收集。同樣,它還能用于執行 pre-mortem 清除操作。 PhantomReference 必須與 ReferenceQueue 類一起使用。需要 ReferenceQueue 是因為它能夠充當通知機制。當垃圾收集器確定了某個對象是虛可及對象時, PhantomReference 對象就被放在它的 ReferenceQueue 上。將 PhantomReference 對象放在 ReferenceQueue 上也就是一個通知,表明 PhantomReference 對象引用的對象已經結束,可供收集了。這使您能夠剛好在對象占用的內存被回收之前采取行動。
在某些場合引用類還是很有用的,具體可以參考文章Java2引用類使用指南(http://www-128.ibm.com/developerworks/cn/java/j-refs/index.html)。
6) 盡可能少的減少不必要對象的生成
盡可能減少在循環中創建對象,使用StringBuffer而不要使用String來做連接操作等等。
7) 改變對象的創建時機
通過提前創建對象或延遲到使用時再創建對象,來做到性能優化和避免創建過多的對象。