最近到了壓力測試階段(就這樣開著機放著不管一晚上)
每次放過夜第二天回來看到的畫面都是Oops! The game has crashed~
看output log是說用光了memory......
測試機雖說配備不怎麼樣,
好歹也有 4GB RAM
(不過OS是32-bits七除八扣後能用的就1G多吧...)
這遊戲到底有多大胃口能在一夜之間吃掉1G多記憶體...?
好吧,
既然有這問題也不能放著不管,
把之前寫過的code重新審視一遍,
用完的GameObject該Destroy的都Destroy()了、用不著的reference也都指向null了
該做的都做過了,
卻還是看著memory使用量一直只加不減...
後來發原來Unity Pro版有一個很好用的功能:Profiler
果然Pro版就是不同凡響,
打開profiler一看,
吃光memory的真兇就無所遁形了。
當遊戲運後到一定時間後,
所有數值都維持在一定數值,
唯獨Materials只加不滅,
只是十多分鐘數量就爬升到一萬多、佔了十多MB的容量,
如此推算,
要一晚上把電腦推死也不是多難的事。
好了,
找到了兇手,
那麼該如何處置它呢?
理論上Material是GameObject的一部份,
那麼當GameObject被Destroy後Material也應該被處理掉才對,
上網查了一下,
終於找到了類近的答案:
都有使用 Destroy(),那為何還有未銷毀的物件?其實,主要是因為我這裡有對 renderer.material 設置改變其內容,在這個執行時期並不會真的去改變 Project 中的 material,而是產生這個物件實例(instance) 的材質實例以供該物件使用,所以如果只是 Destroy(gameObject) 的話,將會殘留部份物件數,每個產生的物件都殘留一點點的話,慢慢的長時間下來將會累積相當多,記憶體將會不敷使用,所以在 Destroy(gameObject) 的同時,應該也要 Destroy(renderer.material) 才行。結果就是因為在程式中修改過Material的value,
以至Unity產生了一堆Material的instance,
這些instance並不會跟著GameObject一起被銷毀,
而要另外特別處理。
可是場景上的GameObject實在太多,
要每個都特別call幾次Destroy也太累人了,
於是便出現了Resources.UnloadUnusedAssets()。
執行這句後,
Unity會自動將場景中沒有用到的Assets從記憶體中移除,
如此一來便可以專心處理GameObject,不用手動處理每個Components了。
在關卡於關卡之間運行一次UnloadUnusedAssets,
再看一下Profiler,
Material的數量終於不再步步高昇了。
ref:
http://godstamps.blogspot.hk/2011/04/unity_30.html
http://supersegfault.com/managing-memory-in-unity3d/
http://docs.unity3d.com/Documentation/ScriptReference/Resources.UnloadUnusedAssets.html

沒有留言:
張貼留言