在程序里面經常會遇到的一個問題是短時間內創建大量的對象,導致內存緊張,從而觸發GC導致性能問題。對于這個問題,我們可以使用對象池技術來解決它。通常對象池中的對象可能是bitmaps,views,paints等等。關于對象池的操作原理,不展開述說了,請看下面的圖示:
使用對象池技術有很多好處,它可以避免內存抖動,提升性能,但是在使用的時候有一些內容是需要特別注意的。通常情況下,初始化的對象池里面都是空白的,當使用某個對象的時候先去對象池查詢是否存在,如果不存在則創建這個對象然后加入對象池,但是我們也可以在程序剛啟動的時候就事先為對象池填充一些即將要使用到的數據,這樣可以在需要使用到這些對象的時候提供更快的首次加載速度,這種行為就叫做預分配。使用對象池也有不好的一面,程序員需要手動管理這些對象的分配與釋放,所以我們需要慎重地使用這項技術,避免發生對象的內存泄漏。為了確保所有的對象能夠正確被釋放,我們需要保證加入對象池的對象和其他外部對象沒有互相引用的關系。
工作中需要減少對一些比較耗系統資源對象的創建和初始化工作,因此想到了apache commons-pool工具包。commons-pool包里主要包括三個重要的接口:
ObjectPool用于管理要被池化的對象的借出和歸還;
ObjectPoolFactory用于大量生成相同類型和設置的ObjectPool。
看看下面的例子
一個Connection類,可以想象成一個遠程連接比如數據庫連接等。其中包括創建連接,關閉連接,和一個print方法。
最后是一個測試類
運行測試類,可以看到在第一個循環里雖然循環了10次,一共要了10個MyConnection對象,但是每次返回的都是“conn_1”這個MyConnection對象實例,并且從日志可以看出,makeObject方法只被調用了一次,因此,除了第一次以外,后面的每次申請都是從pool里取出來的。而在第二個循環中,每次申請了兩個MyConnection對象實例,從日志可以看到,在第二個循環里也只調用了一次makeObject方法,并且創建的是conn_2對象實例,這是由于conn_1這個對象已經在第一個循環中被創建了出來,此時只是直接拿出來使用了。這里為了好測試,沒有在第二個循環中做異常處理,真實情況下應該像第一個循環里的代碼類是,在borrowObject和使用pool中對象出現異常時要記得調用invalidateObject方法,并且歸還pool中的對象。