1.背景
在項(xiàng)目中,如果頻繁的通過new 創(chuàng)建對(duì)象,之后讓gc再去回收,這就很容易造成內(nèi)存抖動(dòng),并且頻繁的GC本身也會(huì)消耗內(nèi)存,這樣就很容易在一瞬間造成OOM 內(nèi)存溢出,因?yàn)樗查g申請(qǐng)大量?jī)?nèi)存會(huì)造成內(nèi)存占用突然升高,如果GC 還沒來的及回收,或者頻繁GC,內(nèi)存就會(huì)居高不下,這時(shí)有兩種處理方式,一個(gè)是減少對(duì)象的創(chuàng)建,一個(gè)是復(fù)用對(duì)象。
2. 對(duì)象復(fù)用的基本原理
所謂對(duì)象復(fù)用,就是在對(duì)象創(chuàng)建使用完成后將對(duì)象內(nèi)部的數(shù)據(jù)清除,然后將對(duì)象放到緩存中,等到下次需要?jiǎng)?chuàng)建新對(duì)象時(shí)拿出來復(fù)用,這樣一來一回,只需要占用固定的內(nèi)存就可以,不用每次都去new 一個(gè)對(duì)象申請(qǐng)內(nèi)存,即避免的內(nèi)存抖動(dòng),又避免了頻繁GC,造成可能的穩(wěn)定性問題,但是也有一個(gè)小弊端,就是這塊緩存的對(duì)象所占的對(duì)象是固定的,無法隨著GC來回收,如果需要回收需要我們手動(dòng)處理,所以這個(gè)就需要我們對(duì)使用場(chǎng)景來評(píng)估。
3.如何構(gòu)建一個(gè)對(duì)象池
1.需要有一個(gè)合適的對(duì)象
2.定一個(gè)對(duì)象池的大小
3.處理對(duì)象的回收
4.在核實(shí)的位置獲取對(duì)象池中數(shù)據(jù)并且在使用完成后回收
4. 構(gòu)建一個(gè)對(duì)象池
public class MapCache extends HashMap<String, String> {
private static final String TAG = "MapCache";
//下一條對(duì)象
MapCache next;
public static final Object sPoolSync = new Object ();
// 鏈表首個(gè)對(duì)象
private static MapCache sPool;
//當(dāng)前鏈表個(gè)數(shù)
private static int sPoolSize = 0;
//可緩存的最大空閑對(duì)象數(shù)量,超出后將開始new 對(duì)象,由GC 處理回收
private static final int MAX_POOL_SIZE = 50;
@Override
public void clear() {
recycle ();
}
/**
* 獲取map對(duì)像,如果對(duì)象池存在空閑對(duì)象,就從頭部取出一個(gè)空對(duì)象返回
* 否則new 一個(gè)新對(duì)象。
*/
public static MapCache obtain() {
synchronized (sPoolSync) {
if (sPool != null) {
MapCache m = sPool;
sPool = m.next;
m.next = null;
sPoolSize--;
// 返回鏈表頭部對(duì)象
return m;
}
}
return new MapCache ();
}
/**
* 回收對(duì)象資源
*/
private void recycle() {
super.clear ();
synchronized (sPoolSync) {
if (sPoolSize < MAX_POOL_SIZE) {
next = sPool;
// 將當(dāng)前消息放到鏈表頭部
sPool = this;
//鏈表消息池對(duì)象增加1
sPoolSize++;
}
}
}
public static MapCache createCacheMap(Map<String, String> args) {
MapCache map = obtain ();
for (Map.Entry<?, ?> entry : args.entrySet ()) {
String key = (String) entry.getKey ();
if (key == null) {
Log.e (TAG, "CreateMap error: key == null");
continue;
}
map.put (key, (String) entry.getValue ());
}
return map;
}
private static boolean isMapCache(Map mapCache) {
if (mapCache instanceof MapCache) {
return true;
}
return false;
}
public static MapCache createMap(Map mapCache) {
if (mapCache==null || mapCache.size ()<=0) {
return null;
}
if (isMapCache(mapCache)) {
return (MapCache) mapCache;
}
return createCacheMap (mapCache);
}
}
其實(shí)還算簡(jiǎn)單,基本原理就是定一個(gè)對(duì)象池大小,用一個(gè)鏈表來存儲(chǔ)對(duì)象,然后定義一個(gè)靜態(tài)的頭部對(duì)象sPoolSync,然后定義這個(gè)頭部對(duì)象的next 指向的下一個(gè)對(duì)象,這樣就形成了一個(gè)鏈表的對(duì)象池。
3.1 獲取對(duì)象
當(dāng)通過obtain() 方法來獲取一個(gè)對(duì)象時(shí),如果鏈表中有緩存的對(duì)象數(shù)據(jù)就取出鏈表首部的對(duì)象,然后將他的下一個(gè)對(duì)象指向頭部對(duì)象,然后將對(duì)象池減一個(gè),如果沒有足夠的對(duì)象或者首次調(diào)用,那就new 一個(gè)對(duì)象返回。文章來源:http://www.zghlxwxcb.cn/news/detail-646865.html
3.2 對(duì)象的回收
對(duì)象內(nèi)容的回收recycle()需要根據(jù)不同的對(duì)象定義來處理,就比如我這定義的HashMap,使用完成后只需要調(diào)用clear 方法將原數(shù)據(jù)清空,然后將這個(gè)對(duì)象加入到線程池中即可。
具體操作 就是先將當(dāng)前的鏈表頭部對(duì)象指向當(dāng)前的空閑對(duì)像的next,然后將空閑該對(duì)象 指向頭部靜態(tài)對(duì)像,然后對(duì)象池加一,這樣就順利將空閑對(duì)像加到鏈表頭部。文章來源地址http://www.zghlxwxcb.cn/news/detail-646865.html
到了這里,關(guān)于如何構(gòu)建一個(gè)對(duì)象池并使用的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!