Unity —— 快取池簡單理解
來理解快取池之前,我們先了解一下
C#的記憶體回收機制
:
每次例項化一個物件(在場景上建立一個物件),都會分配一個記憶體空間;
當這個物件被刪除時,僅僅時斷開了對這片空間的引用,此記憶體空間並沒有被釋放掉。
再次建立物件時,會繼續分配其他的記憶體空間,直到記憶體被全部被分配滿。
當記憶體滿了再回過頭看有哪些是不用的“垃圾”,再回收釋放。
這樣的一次釋放,叫做 “
一次GC
”。
所謂垃圾,就是沒有被任何變數、物件引用的內容。
透過是否被引用來確定哪些物件是“垃圾”。
一次GC
正是因為每次GC需要經過大量的計算來判斷是否需要回收,對CPU的消耗較大,所以每次GC都可能會造成卡頓,GC次數一旦多了會嚴重影響玩家的使用體驗,由此出現了
快取池
。
可以把快取池想象成一個衣櫃:
當我們要穿一件衣服(使用一個物件)時,先去衣櫃中看有沒有這件衣服;
如果沒有,我們去買一件(建立一個物件),並放到衣櫃中可以下次使用;
如果有,直接穿這件衣服(使用這個物件),用完後再放回衣櫃(快取池),不丟棄。
每個衣櫃都有很多的格子,裡面分類裝著衣服、褲子、帽子、襪子等(不同的物件型別);
從買衣服到穿衣服都要分門別類放好,每次使用從對應的格子中取出。
如何實現快取池模組呢?
這裡需要用到兩個知識點:
Dictionary List
GameObject 和 Resources 兩個公共類中的API
下面是最簡單的快取池:
public
class
PoolMgr
:
BaseManager
<
PoolMgr
>
{
//宣告快取池容器
public
Dictionary
<
string
,
List
<
GameObject
>>
poolDic
=
new
Dictionary
<
string
,
List
<
GameObject
>>();
//取資源
public
GameObject
GetObject
(
string
name
)
//從哪個格子中取資源
{
GameObject
obj
=
null
;
//這個格子存在且不為空
if
(
poolDic
。
ContainsKey
(
name
)
&&
poolDic
。
ContainsKey
>
0
)
{
obj
=
poolDic
[
name
][
0
];
//找到這個資源
poolDic
[
name
]。
RemoveAt0
(
0
);
//取出(釋放空間)
}
else
{
//格子中沒有這個資源 例項化一個物件 返回出去
obj
=
GameObject
。
Instantiate
(
Resources
。
Load
<
GameObject
>(
name
));
obj
。
name
=
name
;
//把物件名改成和格子同名
}
obj
。
SetActive
(
true
);
//啟用,使其顯示
return
obj
;
}
//還資源
public
void
PushObject
(
string
name
,
GameObject
obj
)
//還到哪個格子裡,還的東西是什麼
{
obj
。
SetActive
(
false
);
//失活,使其隱藏
//裡面有格子
if
(
poolDic
。
ContainsKey
(
name
))
{
poolDic
[
name
]
Add
(
obj
);
}
//裡面沒有格子
else
{
//建立一個格子並新增
poolDic
。
Add
(
name
,
new
List
<
GameObject
>(){
obj
});
}
}
}
快取池的特點:
表面上固定佔用資源不釋放會造成記憶體的浪費
實際上減少了GC的次數,每次記憶體用滿都會GC一次,用了快取池後不用重複的建立、刪除,提高CPU的效能。