刨根問底U3D---從Profile中窺探Unity的內存管理

這篇文章包含哪些內容html

這篇文章從Unity的Profile組件入手,來探討一下Unity在開發環境和正式環境中的內存使用發麪的一些區別,架構

而且給出了最好控制內存的方法(我想你已經知道了...Prefab ) ,以及緣由。性能

 

提早須要閱讀的文章學習

在閱讀本文以前或以後我建議閱讀一下如下幾篇文章測試

 

雨鬆的spa

Unity3D研究院之Assetbundle的實戰 http://www.xuanyusong.com/archives/2405/3d

Unity3D研究院之Assetbundle的原理 http://www.xuanyusong.com/archives/2373htm

 

王巍的對象

Unity 3D中的內存管理 http://onevcat.com/2012/11/memory-in-unity3d/blog

 

星塵(不太肯定是不是原做者 哈)的

Unity3D佔用內存太大的解決方法 http://www.cnblogs.com/88999660/archive/2013/03/15/2961663.html

 


從NGUI的AltasPacker提及

事情的原由仍是由於我在學習使用NGUI(剛接觸Unity沒幾天…), 教程看了看都沒問題 本身動手操做的時候忽然發現...

NGUI 建立UI時候必須都先要建立Altas,那我建立好後的散圖是放在工程裏面呢 仍是要刪掉? 不刪會影響性能麼? 

Google了一番並無發現滿意答案,因此只好本身Profile一下,因而有了以下實驗:

 

1· 首先創建一個空場景,運行,打開Profile. Texture(紋理)部分使用內存2.5MB

 

2·加入一張圖片,場景上不作任何引用。 該圖片顯存展開後大小爲1.5MB , 運行 而後再打開Profile

 

3· 奇蹟的事情發生了... 紋理佔用的內存大小直接變爲 5.8MB 

 

5.8MB- 2.5MB = 3.3MB 很奇怪的一個數,因而我同時懷疑三件事

 

1· 即便素材徹底用不到可是若是工程中有導入則最後會被打包

2· 即便素材沒有被當前場景使用,Unity仍舊會加載 ( Unity啓動時候加載全部的素材??! )

3· Unity對素材在內存中有留有一份引用,3.3MB ~= 1.5MBx2 ( ??! ) 

 

若是以上三點有一個是真的(全是錯的), 那Unity無疑直接變爲廢柴.... 

因而乎就此三點我開始無限的刨根問底.... 

功夫不負有心人吧,終於在一片帖子上面找到了突破口

http://answers.unity3d.com/questions/57909/find-unused-assets-in-project.html

這篇文章說的很清楚,Unity在發佈時候會自動過濾掉未引用的全部資源,而且整個被打包進來的資源能夠經過Log查看

根據文章指出的位置找到Log,而且就上面的工程進行測試,打出Android包  (Mac下Log在 /Users/eran/Library/Logs/Unity/Editor.log , eran爲你的用戶名)

 

這樣的話 第一個心結就解開了, 看來Unity果然沒有這麼傻... 之後使用NGUI製做Atlas時候也不用擔憂是否須要刪除小圖這件事了.

既然知道了只有在真機設備上才能夠進行測試,因而須要再將剛纔作的測試重來一次了,只不過此次是在真機上面.

 

1· 首先創建一個空場景,運行,打開Profile. Texture(紋理)部分使用內存153.0KB

 

能夠注意到,在真機上面運行時候 內存佔用明顯下降了,而且開銷的線很平,再也不像編輯環境同樣會有波動.

 

2·加入一張圖片並放置在場景上面

雖然沒有像想象中的那樣爲1.5MB,不過 既然小於3MB,則Unity3D確定不可能留有一分內存的備份(DRAM一份 VRAM一份,DRAM的用於處理LostConext時候從新上傳GPU). 

這裏面其實還有一個小插曲:

在Android上面 Rendering中顯示 使用的顯存爲0,這點和我理解的3D渲染原理不符呀,一直讓我困惑了好久。後來忽然想到 難道是由於手機是共享顯存的緣由?

果不其然 當我把項目發佈爲PC版本時候 再跑Profile,顯存佔用就有數字了. 而且顯存佔用數和我後面說道的動態剔除還有關係,說明顯存還發生了swap,這塊和所講的事情無關 就不細說了,若是大神對這塊很瞭解 但願指點我一下.

 

ok 繼續說上面提到一嘴的 動態剔除,這個是我無心發現的,

我把上面那張圖加了一個Animation 讓其左右移動,當我真機測試時候,當這張圖片移出屏幕時候DrawCall會減1,也就是隻要屏幕看不到的東西Unity會自動幫你剔除,

減小DrawCall, 其實細想一想, 這個是很正常的一個事情,由於Unity是一個徹底的3D引擎,這也是爲何在Unity裏面沒有像素 進來單位是Unit,沒有屏幕的寬高,只能調整攝像機的視野. 

相比之下以前用的Starling,Cocos,雖然底層也在使用GPU進行渲染,可是他的總體引擎架構是基於2D的,因此天然沒法在底層完成這種自動剔除以及顯存交換的行爲.相比之下Unity要優越許多.

就此Unity的一大謎題得以解開,根據上面的實驗我獲得了以下兩條結論

 

結論: 即便項目中有許多未使用的圖片,只要未放置在特殊文件夾下(Resource,StreamingAssets)而且沒有被Prefab引用,最終導出時候不會被打包,更不會佔用顯存,可是在開發階段會.

 

結論: Unity 會自行對移出場景的對象進行剔除從而減小DrawCall

 


Prefab 最好的管理內存(顯存)的方式

個人刨根問底行爲到這裏並無結束, 既然知道了Unity如何加載素材,那他何時卸載呢?

我又作了以下實驗:

 

創建兩個場景,SceneA,SceneB. 在SceneA中加載一張紋理,同時提供一個跳轉到SceneB的按鈕. 

點擊按鈕跳轉到SceneB,SceneB是一個空場景 什麼都不放. 

預期的是當切換到SceneB時候SceneA中所佔用的顯存應該會被釋放,不過結果卻又是讓人大失所望... 仍舊沒有變化

即便我在SceneB中調用GC都沒用(其實看過GC介紹的朋友也應該知道在那裏調GC原本就應該沒用)

 

最後又是一通Google,不過此次沒有像上次那麼走運 沒有任何的收穫,這也是我後來轉向開始研究Prefab的緣由. 不過仍是繼續把這裏說完. 

又是一次意外的測試,我發現當我再創建一個SceneC時候, 由SceneA->SceneB->SceneC 這個時候 SceneA中的顯存會獲得釋放. 就此問題我還發了一個Question. 

有個朋友給了他項目上的證明,Unity確實如此 http://ask.unitymanual.com/question/36097

 

既然Unity自動管理的內存須要跨兩個場景才能消除,那咱們有沒有辦法本身控制呢? 方法是有的 那就是使用Prefab.

如何建立及如何使用Prefab 鬆雨的那兩篇文章已經說的很是明白了,我就不重複造輪子了.

 

結論: Unity自身的顯存回收是須要通過跨兩個場景,若是使用Prefab在調用assetBundle.Unload (true)時候能夠釋放顯存。

 

以上是我這幾天經過實驗摸索的一些經驗,但願能對你有所幫助。若是哪裏說的不對還請大神指出

謝謝

相關文章
相關標籤/搜索