【Unity】運行時刻資源管理

Unity運行時刻資源管理

 

----------------------------------------------------------------------------------------

Asset Bundles    

製作:BuildPipeline.BuildAssetBundle()    

加載:AssetBundle.Load()    

卸載:AssetBundle.Unload(bool unloadAllLoadedObjects)        

unloadAllLoadedObjects = true:釋放解壓數據,所有已實例化的資源亦被釋放。        

unloadAllLoadedObjects = false:釋放解壓數據,已實例化的資源不釋放。

Resource Folders    

製作:Project視圖中任意名爲“Resources”文件夾下的資源,無論場景中是否用到。    

加載:Resources.Load()   

  卸載:Resources.UnloadUnusedAssets(),實例通過Object.Destroy()釋放。    

工作方式:         所有Resources資源及其相關資源都存儲於resources.assets中,但如果有資源被某場景使用,該資源則被存儲於該場景對應的sharedassets<0~n>.assets中。         如果編譯目標平臺爲Streaming Web Player,則情況略有不同。你可以在設置中通過First Streamed Level With Resources一項指定所有Resources資源跟隨哪一場景(Level)加載。在該模式下,所有先於“First streamed Level”加載的場景,用到的Resource資源同上,都存儲於其對應的sharedassets中;後於“First streamed Level”加載的場景,其用到的Resource資源,卻存儲於resources.assets中。

----------------------------------------------------------------------------------------
Streaming  Web Players    

該模式中的Streaming是以場景(Level)爲單位的,你可以在編譯設置中指定各個場景的載入順序,Unity Web  Player會按該順序自發異步加載各場景。同時,Unity也提供了通過WWW加載.unity3d場景文件的API,使開發者對場景加載有更靈活的控制權。       實際上,WWW可以用於網絡下載任意資源(紋理、文本、二進制文件),視頻和音頻也可以通過WWW下載,而且可以做到邊下載邊播放。
AssetBundle

----------------------------------------------------------------------------------------

想打包進AssetBundle中的二進制文件,其文件名後綴必須爲“.bytes”,Unity會將其視爲TextAssets對待。
AssetBundle  bundle =  www.assetBundle;

獲取WWW.assetBundle的一刻,由WWW下載的數據壓縮包被解壓,AssetBundle對象被創建,此時你可以用AssetBundle.Load()實例化資源了。
除非使用AssetBundle.LoadAll()獲取所有資源,否則無法得到一個AssetBundle中的資源列表。一般做法是在該AssetBundle中放置一個定好名稱的TextAsset,在其中維護一份所有資源的名稱列表。
一個AssetBundle包可以引用其他AssetBundle包中的資源。製作時,需要調用BuildPipeline.PushAssetDependencies()和BuildPipeline.PopAssetDependencies()函數對;加載時,被引用的包需要先於引用包加載。 另外,重編這種包需要開啓BuildAssetBundleOptions.DeterministicAssetBundle,以保證每次重編時所使用的資源ID都是一樣的。
你可以在一個遊戲裏使用另一個遊戲的AssetBundle,前提是該AssetBundle中所引用的資源,要麼存在於該AssetBundle中,要麼已經被載入了遊戲中。爲確保AssetBundle引用的資源被編進同包中,製作時可以使用BuildAssetBundleOptions.CollectDependencies選項。

----------------------------------------------------------------------------------------
AssetDatabase Unity  Editor使用AssetDatabase維護項目中的所有資源文件,Unity使用這套API取代傳統的filesystem。這是一個Editor類,所以只有在名爲“Editor”的文件夾下的Script中才有用。

BuildPipeline.BuildStreamedSceneAssetBundle()或BuildPipeline.BuildPlayer(...,  BuildOptions.BuildAdditionalStreamedScenes)生成的場景包,使用WWW下載後,只需調用WWW.assetBundle,而不需AssetBundle.LoadAll(),即可激活包中的場景,即調用WWW.assetBundle後,你就可以通過Application.LoadLevel()來載入場景了。

 

 

http://blog.csdn.net/ox_thedarkness/article/details/9197453

分離資源管理

參考

1.Unity3D佔用內存太大的解決方法 - 星塵

 

討論AssetBundle-Resources-GameObject 的生命週期問題。對AssetBundle.Unload,Instantiate,Destory,UnloadUnusedAsset有詳細的辨析。

 

http://www.cnblogs.com/88999660/archive/2013/03/15/2961663.html

 

討論基於Unity3d 4.1.5,不定時更新。

基本信息

美術資源應導出爲AssetBundle文件。這種AssetBundle有兩種存儲方式:可以是未壓縮的,也可以使用7z算法壓縮,默認壓縮。以我手頭的一個蒙皮動畫角色爲例,壓縮後文件大小由800K減少到260K。導出過程中各個成分佔的文件比例會在Logs中打印出來,以供分析和優化。
AssetBundle有下面兩個主要的加載方法:

  • AssetBundle.CreateFromFile只能加載未壓縮的文件。根據文檔的說法,該方法是最快的加載方法,但是不知道這個"fast"是指“performace”還是"easy"。如果該算法是流式加載,可能確實是最快的,因爲其他加載方法都有中間產物,例如CreateFromMemory或者WWW需會產生額外的byte[]。

  • AssetBundle.CreateFromMemory異步加載內存中二進制字節。這帶來的好處是,硬盤上的文件可以使用自定義的方式組織、壓縮和打包。

 

性能和內存泄露

加載過程中會產生三級中間產物:

 

  1. AssetBundle

  2. Asset-Object:所有AssetBundle.Load*創建的Object,包括mainAsset

  3. Cloned-Object:Instantiate一個Asset-Object之後產生的Object

其中,AssetBundle是資源的靜態二進制存檔形式。此時資源並沒有真正讀出,只有執行Load操作資源纔會被創建到Resouces系統中。Resources系統管理Asset-Object亦即實際的資源,包括貼圖、mesh、Asset-GameObject。其中的Asset-GameObject非常類似Cloned-GameObject,但是無法掛載到場景中,無法被Destroy銷燬,只能用Instantiate生成Cloned-Object。實際我們看見的是Cloned-Object。

 

1. AssetBundle需要手工管理

 

Unity3d並沒有追蹤每個資源的來源。假如你反覆加載同一個資源文件,每次AssetBundle.CreateFromFile/Memory都會創建一個新的AssetBundle,包含新的貼圖、新的模型。爲了減少這類誤用,Unity在每個資源包的二進制內容中添加了一個隨機包標誌(包標誌是導出時添加的,即使是同一個資源,每次導出都是不同的包)。Unity3d通過比較包標誌的方式,禁止同時存在兩個讀取了相同資源包。若一個資源包對應的AssetBundle沒有Unload,再次創建新的該資源的AssetBundle時會拋出錯誤:

 

  • The asset bundle '<unknown>' can't be loaded because another asset with the same files are already loaded

 

但是Unity只是簡單在AssetBundle創建時做了檢查,在Asset-Object級沒有記錄包標誌來源,也不會合並相同資源。

  • 有一種不良做法:每次都重新讀取資源包之後立即釋放包,將Instantiate出來的角色放在場景上。這種做法很簡潔不會引起內存泄漏,但是對於mmo rpg而言,場景上經常會有很多相同角色。每次重新讀取的資源包都會產生獨立的Asset-Object,結果就是場景上的20只史萊姆會擁有20份骨骼、20份貼圖、20份材質、佔用20份顯存。

總的來說,項目框架需要手工管理AssetBundle,保證同一套資源不重複加載。

2. Asset-Object和Cloned-Object管理

所有AssetBundle.Load*加載的UnityEngine.Object,我們稱爲Asset-Object,與Instantiate創造出的 Cloned-Object相對應。

這兩個概念在[1]的第一張配圖中分別標記爲”Asset-*“和”*-複製“。對成員mainAsset的訪問實際上是完整的加載函數調用,爲手工調用Load的簡化版。另外經測試,反覆Load同一個資源至少沒有額外資源泄露。

在Unity自帶的Profile系統中,Memory欄下 Textures/Meshes/Materials/AnimationClips/AudioClips指的就是Asset-Object。例如,從一個史萊姆Instantiate出很多史萊姆並不會增加Textures或者Meshes計數。

雖然都是UnityEngine.Object,但是Asset-Object和Cloned-Object本質是不同的。例如,如果對Asset-Object執行Destroy,系統會報錯:

 

  • Destroying assets is not permitted to avoid data loss.

 

Asset-Object是由Resources系統管理的,包括Asset中的Texture、AnimationClips等,爲內存開銷的主要來源。Resources系統使用弱引用管理Asset-Object,同時提供了Resources.UnloadUnusedAsset()以刪除沒有不再被強引用的Asset-Object。注意他檢查的是所有強引用,並不限於場景中實際GameObject,所以如果你的代碼中記錄了的Asset表,還有某些代碼的意外引用都會阻止這些資源被Resources系統釋放。

 

  • 有一種錯誤理解:我們只需要AssetBundle.Unload(false),然後在刪除場景內容時Object.Destroy(),這樣是否就沒有泄漏了?答案是否定的,前者刪除了AssetBundle,後者刪除了Cloned-Object,但是Asset-Object還沒有刪除。Asset-Object由Resources系統管理,需要手工調用Resources.UnloadUnusedAsset()或者其他類似接口才能刪除。

  • 正確的資源完全釋放方法:AssetBundle.Unload(true)——釋放AssetBundle和Asset-Object,而後Object.Destroy()釋放Cloned-Object。

3. 場景管理

導出場景只能用BuildStreamedSceneAssetBundle,不能使用BuildAssetBundle。場景文件仍然可以用CreateFromMemory讀取,只不過Clone的時候必須使用Application.LoadLevel。而且LoadLevel過程和結果貌似不可控,比如你從程序上並不能得到“場景加載完畢”或者“場景的內容是什麼”這樣的信息。


編譯連接和發佈

參考

兩生花:Unity3d中使用log4net

裏面提到C#進行本地配置的問題,看不大懂先掛着,有時間再去研究

http://www.cnblogs.com/koalaylj/articles/2670629.html

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章