Unity3D 游戲開發之內存優化


 

項目的性能優化主要圍繞CPU、GPU和內存三大方面進行。

無論是游戲還是VR應用,內存管理都是其研發階段的重中之重。

然而,在我們測評過的大量項目中,90%以上的項目都存在不同程度的內存使用問題。就目前基於Unity引擎開發的移動游戲和移動VR游戲而言,內存的開銷無外乎以下三大部分:1.資源內存占用;2.引擎模塊自身內存占用;3.托管堆內存占用。

如果您的項目存在內存問題,一定逃不出以上三種情況。今天,我們就這三種情況逐一進行解釋。

資源內存占用

在一個較為復雜的大中型項目中,資源的內存占用往往占據了總體內存的70%以上。因此,資源使用是否恰當直接決定了項目的內存占用情況。一般來說,一款游戲項目的資源主要可分為如下幾種:紋理(Texture)、網格(Mesh)、動畫片段(AnimationClip)、音頻片段(AudioClip)、材質(Material)、着色器(Shader)、字體資源(Font)以及文本資源(Text Asset)等等。其中,紋理、網格、動畫片段和音頻片段則是最容易造成較大內存開銷的資源。

一、紋理

紋理資源可以說是幾乎所有游戲項目中占據最大內存開銷的資源。一個6萬面片的場景,網格資源最大才不過10MB,但一個2048x2048的紋理,可能直接就達到16MB。因此,項目中紋理資源的使用是否得當會極大地影響項目的內存占用。 那么,紋理資源在使用時應該注意哪些地方呢?

(1) 紋理格式

紋理格式是研發團隊最需要關注的紋理屬性。因為它不僅影響着紋理的內存占用,同時還決定了紋理的加載效率。一般來說,我們建議開發團隊盡可能根據硬件的種類選擇硬件支持的紋理格式,比如Android平台的ETC、iOS平台的PVRTC、Windows PC上的DXT等等。因此,我們在UWA測評報告中,將紋理格式進行詳細羅列,以便開發團隊進行快速查找,一步定位。

 

在使用硬件支持的紋理格式時,你可能會遇到以下幾個問題:

  • 色階問題 由於ETC、PVRTC等格式均為有損壓縮,因此,當紋理色差范圍跨度較大時,均不可避免地造成不同程度的“階梯”狀的色階問題。因此,很多研發團隊使用RGBA32/ARGB32格式來實現更好的效果。但是,這種做法將造成很大的內存占用。比如,同樣一張1024x1024的紋理,如果不開啟Mipmap,並且為PVRTC格式,則其內存占用為512KB,而如果轉換為RGBA32位,則很可能占用達到4MB。所以,研發團隊在使用RGBA32或ARGB32格式的紋理時,一定要慎重考慮,更為明智的選擇是盡量減少紋理的色差范圍,使其盡可能使用硬件支持的壓縮格式進行儲存。
  • ETC1 不支持透明通道問題 在Android平台上,對於使用OpenGL ES 2.0的設備,其紋理格式僅能支持ETC1格式,該格式有個較為嚴重的問題,即不支持Alpha透明通道,使得透明貼圖無法直接通過ETC1格式來進行儲存。對此,我們建議研發團隊將透明貼圖盡可能分拆成兩張,即一張RGB24位紋理記錄原始紋理的顏色部分和一張Alpha8紋理記錄原始紋理的透明通道部分。然后,將這兩張貼圖分別轉化為ETC1格式的紋理,並通過特定的Shader來進行渲染,從而來達到支持透明貼圖的效果。該種方法不僅可以極大程度上逼近RGBA透明貼圖的渲染效果,同時還可以降低紋理的內存占用,是我們非常推薦的使用方式。

當然,目前已經有越來越多的設備支持了OpenGL ES 3.0,這樣Android平台上你可以進一步使用ETC2甚至ASTC,這些紋理格式均為支持透明通道且壓縮比更為理想的紋理格式。如果你的游戲適合人群為中高端設備用戶,那么不妨直接使用這兩種格式來作為紋理的主要存儲格式。

(2)紋理尺寸

一般來說,紋理尺寸越大,則內存占用越大。所以,盡可能降低紋理尺寸,如果512x512的紋理對於顯示效果已經夠用,那么就不要使用1024x1024的紋理,因為后者的內存占用是前者的四倍。因此,我們在UWA測評報告中,將紋理的尺寸進行詳細展示,以便開發團隊進行快速檢測。

Mipmap旨在有效降低渲染帶寬的壓力,提升游戲的渲染效率。但是,開啟Mipmap會將紋理內存提升1.33倍。對於具有較大縱深感的3D游戲來說,3D場景模型和角色我們一般是建議開啟Mipmap功能的,但是在我們的測評項目中,經常會發現部分UI紋理也開啟了Mipmap功能。這其實就沒有必要的,絕大多數UI均是渲染在屏幕最上層,開啟Mipmap並不會提升渲染效率,反倒會增加無謂的內存占用。因此,建議研發團隊在UWA的測評報告中通過Mipmap一項進行排序,詳細檢測開啟Mipmap功能的資源是否為UI資源。

(4) Read & Write

一般情況下,紋理資源的“Read & Write”功能在Unity引擎中是默認關閉的。但是,我們仍然在項目深度優化時發現了不少項目的紋理資源會開啟該選項。對此,我們建議研發團隊密切關注紋理資源中該選項的使用,因為開啟該選項將會使紋理內存增大一倍。

 

 

二、網格

網格資源在較為復雜的游戲中,往往占據較高的內存。對於網格資源來說,它在使用時應該注意哪些方面呢?

(1) Normal、Color和Tangent

在我們深度優化過的大量項目中,Mesh資源的數據中經常會含有大量的Color數據、Normal數據和Tangent數據。這些數據的存在將大幅度增加Mesh資源的文件體積和內存占用。其中,Color數據和Normal數據主要為3DMax、Maya等建模軟件導出時設置所生成,而Tangent一般為導入引擎時生成。

更為麻煩的是,如果項目對Mesh進行Draw Call Batching操作的話,那么將很有可能進一步增大總體內存的占用。比如,100個Mesh進行拼合,其中99個Mesh均沒有Color、Tangent等屬性,剩下一個則包含有Color、Normal和Tangent屬性,那么Mesh拼合后,CombinedMesh中將為每個Mesh來添加上此三個頂點屬性,進而造成很大的內存開銷。正因如此,我們在UWA測評報告中為每個Mesh展示了其Normal、Color和Tangent屬性的具體使用情況,研發團隊可以直接針對每種屬性進行排序查看,直接定位出現冗余數據的資源。

 

 

一般來說這些數據主要為Shader所用,來生成較為酷炫的效果。所以,建議研發團隊針對項目中的網格資源進行詳細檢測,查看該模型的渲染Shader中是否需要這些數據進行渲染。

限於篇幅,我們今天只針對紋理和網格資源進行詳細介紹,對於動畫片段、音頻片段等其他資源,建議您直接通過UWA測評報告中進行查看。同時,我們會在后續的資源專題中進行詳細講解,敬請期待。

引擎模塊自身占用

引擎自身中存在內存開銷的部分紛繁復雜,可以說是由巨量的“微小”內存所累積起來的,比如GameObject及其各種Component(最大量的Component應該算是Transform了)、ParticleSystem、MonoScript以及各種各樣的模塊Manager(SceneManager、CanvasManager、PersistentManager等)...

一般情況下,上面所指出的引擎各組成部分的內存開銷均比較小,真正占據較大內存開銷的是這兩處:WebStreamSerializedFile。其絕大部分的內存分配則是由AssetBundle加載資源所致。簡單言之,當您使用new WWW或CreateFromMemory來加載AssetBundle時,Unity引擎會加載原始數據到內存中並對其進行解壓,而WebStream的大小則是AssetBundle原始文件大小 + 解壓后的數據大小 + DecompressionBuffer(0.5MB)。同時,由於Unity 5.3版本之前的AssetBundle文件為LZMA壓縮,其壓縮比類似於Zip(20%-25%),所以對於一個1MB的原始AssetBundle文件,其加載后WebStream的大小則可能是5~6MB,因此,當項目中存在通過new WWW加載多個AssetBundle文件,且AssetBundle又無法及時釋放時,WebStream的內存可能會很大,這是研發團隊需要時刻關注的。

 

 作者:張鑫 鏈接:https://zhuanlan.zhihu.com/p/21913770 來源:知乎 著作權歸作者所有。商業轉載請聯系作者獲得授權,非商業轉載請注明出處。

對於SerializedFile,則是當你使用LoadFromCacheOrDownload、CreateFromFile或new WWW本地AssetBundle文件時產生的序列化文件。

對於WebStream和SerializedFile,你需要關注以下兩點:

  • 是否存在AssetBundle沒有被清理干凈的情況。開發團隊可以通過Unity Profiler直接查看其使用具體的使用情況,並確定Take Sample時AssetBundle的存在是否合理;
  • 對於占用WebStream較大的AssetBundle文件(如UI Atlas相關的AssetBundle文件等),建議使用LoadFromCacheOrDownLoad或CreateFromFile來進行替換,即將解壓后的AssetBundle數據存儲於本地Cache中進行使用。這種做法非常適合於內存特別吃緊的項目,即通過本地的磁盤空間來換取內存空間。

注意:關於AssetBundle的詳細管理機制,建議查看我們之前的AssetBundle技術文章

托管堆內存占用

對於目前絕大多數基於Unity引擎開發的項目而言,其托管堆內存是由Mono分配和管理的。“托管” 的本意是Mono可以自動地改變堆的大小來適應你所需要的內存,並且適時地調用垃圾回收(Garbage Collection)操作來釋放已經不需要的內存,從而降低開發人員在代碼內存管理方面的門檻。

但是這並不意味着研發團隊可以在代碼中肆無忌憚地開辟托管堆內存,因為目前Unity所使用的Mono版本存在一個很嚴重的問題,即:Mono的堆內存一旦分配,就不會返還給系統。這意味着Mono的堆內存是只升不降的。舉個例子,項目運行時,在場景A中開辟了60MB的托管堆內存,而到下一場景B時,只需要使用20MB的托管堆內存,那么Mono中將會存在40MB空閑的堆內存,且不會返還給系統。這是我們非常不願意看到的現象,因為對於游戲(特別是移動游戲)來說,內存的占用可謂是寸土寸金的,讓Mono毫無必要地鎖住大量的內存,是一件非常浪費的事情。所以,我們在UWA測評報告中,為研發團隊統計了測試過程中累積的函數堆內存分配量,大家只需要通過查看堆內存分配Top10的函數,即可快速對其底層代碼實現進行查看,定位是否有分配不必要堆內存的代碼存在。

 

 作者:張鑫 鏈接:https://zhuanlan.zhihu.com/p/21913770 來源:知乎 著作權歸作者所有。商業轉載請聯系作者獲得授權,非商業轉載請注明出處。

讀到這里,你可能會產生這樣的疑問:我知道了哪些函數的堆內存分配大了,但是我該如何去進一步定位不必要的堆內存呢?

這是我們經常遇到的問題,所以在我們的深度項目優化服務中,我們都會直接進駐到項目團隊,現場查看項目代碼並對問題代碼進行定位。在經過了大量的深度檢測后,我們發現用戶不必要的堆內存分配主要來自於以下幾個方面:

  • 高頻率地 New Class/Container/Array等。研發團隊切記不要在Update、FixUpdate或較高調用頻率的函數中開辟堆內存,這會對你的項目內存和性能均造成非常大的傷害。做個簡單的計算,假設你的項目中某一函數每一幀只分配100B的堆內存,幀率是1秒30幀,那么1秒鍾游戲的堆內存分配則是3KB,1分鍾的堆內存分配就是180KB,10分鍾后就已經分配了1.8MB。如果你有10個這樣的函數,那么10分鍾后,堆內存的分配就是18MB,這期間,它可能會造成Mono的堆內存峰值升高,同時又可能引起了多次GC的調用。在我們的測評項目中,一個函數在10分鍾內分配上百MB的情況比比皆是,有時候甚至會分配上GB的堆內存。
  • Log輸出。我們發現在大量的項目中,仍然存在大量Log輸出的情況。建議研發團隊對自身Log的輸出進行嚴格的控制,僅保留關鍵Log,以避免不必要的堆內存分配。對此,我們在UWA測評報告中對Log的輸出進行了詳細的檢測,不僅提供詳細的性能開銷,同時占用Log輸出的調用路徑。這樣,研發團隊可直接通過報告定位和控制Log的輸出。

 

 UIPanel.LateUpdate。這是NGUI中CPU和堆內存開銷最大的函數。它本身只是一個函數,但NGUI的大量使用使它逐漸成為了一個不可忽視規則。該函數的堆內存分配和自身CPU開銷,其根源上是一致的,即是由UI網格的重建造成。因此,其對應的優化方法是直接查看CPU篇中的UI模塊講解。

作者:張鑫 鏈接:https://zhuanlan.zhihu.com/p/21913770 來源:知乎 著作權歸作者所有。商業轉載請聯系作者獲得授權,非商業轉載請注明出處。

關於代碼堆內存分配的注意點還有很多,比如String連接、部分引擎API(GetComponent)的使用等等,這些已經是老生常談了,鑒於篇幅限制不在此處多作介紹,大家感興趣可以Google自行搜索。后續也會有專門的代碼效率專題講解,敬請關注。

UWA測評的內存標准

在大家使用過UWA之后,對於UWA推薦的內存標准值提出了很大的疑惑。在這里,我們也分享下UWA內存標准的制定規則。

(1)150MB的總體內存標准主要由以下兩個因素得出:

  • 經過了大量的項目優化后總結而得。其實,對於目前市場主流的Unity游戲來說,其內存占用主要集中在120~200MB。同時,顧及到iPhone4和512MB/768MB等低端Android機型,其應用的自身總體內存占用不可超過200MB(iPhone4的安全線應該在180MB左右),所以我們將Reserved Total設定在150MB,這是Unity引擎的自身內存分配,以保證App在使用到的系統庫后,其OS中的整體內存也在200MB以下。
  • 某些渠道對Android游戲的PSS內存進行了嚴格的限制。一般要求游戲的PSS內存在200MB以下。這是我們將Reserved Total內存設定在150MB的另外一個重要原因。

(2)當總體內存設定為150MB后,我們進一步對其具體分配進行了設定。但需要說明的是,這里的內存分配其實並沒有嚴格的公式來進行論證,僅是我們在大量的項目優化工作中提煉出的經驗值。目前,項目較為合理的內存分配如下:

  • 紋理資源: 50 MB
  • 網格資源: 20 MB
  • 動畫片段: 15 MB
  • 音頻片段: 15 MB
  • Mono堆內存: 40 MB
  • 其他: 10 MB

需要指出的是,150MB中並沒有涵蓋較為復雜的字體文件(比如微軟雅黑)以及Text Asset,這些需要根據游戲需求而定。

(3)目前的UWA內存標准是較為苛刻的,對於中高端設備而言,其內容允許量其實要比150MB要大得多。但我們堅持認為,在研發過程中,一個嚴苛的標准對於一個項目來說是一件好事。至少,它可以為大家提個醒,讓大家時刻關注自己的問題。據我們了解,目前的三到五線城市,其低端手機的覆蓋率還是相當高的。同時,對於中高端移動設備,我們仍在不斷試驗和研究中。我們希望在不久的將來可以做到針對各種不同檔次的機型都給出一個更為合理的推薦值,從而讓大家更為簡單地對內存進行管理。

以上所說的是游戲項目中主要的內存分配情況,希望讀到此處的你,可以更加了解Unity項目的內存開銷和潛在問題,並對自己的項目進行更有針對性的檢測。

 

有三個更為重要的地方需要研發團隊關注:內存泄露、Mono無效堆內存開銷和資源冗余。這幾乎是所有團隊在研發過程中都會遇到的問題。今天我們就來詳細說一說這些問題的解決方案。

作者:張鑫 鏈接:https://zhuanlan.zhihu.com/p/21913837 來源:知乎 著作權歸作者所有。商業轉載請聯系作者獲得授權,非商業轉載請注明出處。

內存泄露

內存泄露是開發人員在項目研發過程中最常見也最不願遇到的問題。就目前來看,大家對於判斷項目是否存在內存泄露仍然存在一些誤區:

  • 誤區一 我的項目進出場景前后內存回落不一致,比如進入場景后,內存增加40MB,出來后下降30MB,仍有10MB內存沒有返回給系統,即說明內存存在泄露情況。
  • 誤區二 我的項目在進出場景前后,Unity Profiler中內存回落正常,但Android的PSS數值並沒有完全回落(出場景后的PSS值高於進場景前的PSS值),即說明內存存在泄露情況。

以上是我們遇到的開發團隊反饋給我們的典型問題。相信大多數開發團隊都會遇到類似的情況。在此有必要說明一下,以上兩種情況均不能表明內存存在泄漏問題。即便內存在一段時間始終保持增長的趨勢,也不能簡單地判定其存在內存泄露。因為造成內存不能完全回落的情況有很多,比如資源加載后常駐內存以備后續使用、Mono堆內存的只升不降等等,這些均可造成內存無法完全回落。一般來說,我們推薦的判斷內存是否泄漏的方法如下:

一、檢查資源的使用情況,特別是紋理、網格等資源的使用

在我們進行過的項目深度優化過程中,資源泄漏是內存泄露的主要表現形式,其具體原因是用戶對加載后的資源進行了儲存(比如放到Container中),但在場景切換時並沒有將其Remove或Clear,從而無論是引擎本身還是手動調用Resources.UnloadUnusedAssets等相關API均無法對其進行卸載,進而造成了資源泄露。對於這種情況的排查相當困難,這是因為項目中的資源量過於巨大,泄露資源往往很難定位。因此,我們在UWA測評報告中對項目中的每個資源都進行了詳細的監控,並通過“生命周期”這一衡量指標讓大家可以清楚地了解到每個資源在項目運行過程中的使用范圍。

 

這樣,大家可以通過資源的“生命周期”屬性來快速查看有哪些資源是“常駐”內存的,並且判斷該資源是“預加載”資源還是“泄露”資源。

同時,項目中所使用的總資源數量往往是成百上千的,讓大家逐個資源檢查過來是一件很費力的事情。所以,我們推出了資源的“場景比較”功能。建議大家通過以下兩種方式進行資源比較,以便更快地找到存在“泄露”問題的資源

  • 同種類型場景或同一場景進行比較

一般來說,同種場景或同一場景的資源使用應該是較為固定的,比如游戲項目中的主城場景或主界面場景。通過比較不同時刻同一場景的資源信息,可以快速幫你找到其資源使用的差異情況。這樣,你只需判斷這些“差異”資源的存在是否合理,即可快速判定是否存在資源泄露,已經具體的泄露資源。

  • 不同類型場景進行比較

除一些常駐資源外,不同類型的場景,其資源使用是完全不同的。比如,游戲中主城和戰斗副本的資源,除少部分常駐內存的資源外,二者使用的絕大部分資源應該是不一致的。所以,通過比較兩種不同類型的場景,你可以直接查看比較結果中的“共同資源”,並判斷其是否確實為預先設定好的常駐資源。如果不是,則它很可能是“泄露”資源,需要你進一步查看項目的資源管理是否存在漏洞。

 

二、通過Profiler來檢測WebStream或SerializedFile的使用情況

AssetBundle的管理不當也會造成一定的內存泄露,即上一場景中使用的AssetBundle在場景切換時沒有被卸載掉,而被帶入到了下一場場景中。對於這種情況,建議直接通過Profiler Memory中的Take Sample來對其進行檢測,通過直接查看WebStream或SerializedFile中的AssetBundle名稱,即可判斷是否存在“泄露”情況。

 

三、通過Android PSS/iOS Instrument反饋的App線程內存來查看

承接上述“誤區二”中的說法,“Unity Profiler中內存回落正常,但Android的PSS數值並沒有完全回落”是有可能的,這是因為Unity Profiler反饋的是引擎的真實分配的物理內存,而PSS中記錄的則包括系統的部分緩存。一般情況下,Android或iOS並不會及時將所有App卸載數據進行清理,為了保證下次使用時的流暢性,OS會將部分數據放入到緩存,待自身內存不足時,OS Kernel會啟動類似LowMemoryKiller的機制來查詢緩存甚至殺死一些進程來釋放內存。因此,並不能通過一兩次的PSS內存沒有完全回落來說明內存泄露問題。

我們推薦的測試方式是在兩個場景之間來回不停切換,比如主城和戰斗副本間。理論上來說,多次切換同樣的場景,如果Profiler中顯示的Unity內存回落正常,那么其PSS/Instrument的內存數值波動范圍也是趨於穩定的,但如果出現了PSS/Instrument內存持續增長的情況,則需要大家注意了。這可能有兩種可能:

  • Unity引擎自身的內存泄露問題。這種概率很小,之前僅在少數版本中出現過。

  • 第三方插件在使用時出現了內存泄露。這種概率較大,因為Profiler僅能對Unity自身的內存進行監控,而無法檢測到第三方庫的內存分配情況。因此,在出現上述內存問題時,建議大家先對自身使用的第三方庫進行排查。

無效的Mono堆內存開銷

目前,Unity所使用的Mono版本中存在一個較大的問題,即內存一旦分配,則不會再返回給系統。這就衍生出另外一個問題—— 無效的Mono堆內存。它是Mono所分配的堆內存,但卻沒有被真正利用上,因此稱之為“無效”。那么,如何查看我的項目中是否存在較大量的“無效堆內存”呢

在UWA測評報告中,我們提供了內存隨項目運行的分配情況,如下圖所示。其中,藍線和紫線的分離情況,反映了無效堆內存的分配大小。比如,圖中所選中時刻,藍線的Reserved Total為當前項目所占據的總物理內存,而紫線的Used Total為當前項目所使用的總物理內存,這說明當前項目中的空閑內存為57.1MB(200.4-143.3),而這其中主要由兩部分組成,空閑的Unity引擎內存和無效的Mono堆內存。其中,空閑的Unity內存為17.1MB(92.0-74.9),所以當前所選幀的無效Mono堆內存為40.0MB。並且,從圖中可以看出,藍線和紫線在運行過程中一直分得較開,這說明一直存在不小的Mono堆內存處於“無效”狀態。這是一件很浪費的事情,特別是對於內存寸土寸金的移動設備而言。

 

 

那么,我們應該如何避免或減少過多“無效堆內存”的分配呢?我們推薦的做法如下:

  • 避免一次性堆內存的過大分配。Mono的堆內存也是“按需”逐步進行分配的。但如果一次性開辟過大堆內存,比如New一個較大Container、加載一個過大配置文件等,則勢必會造成Mono的堆內存直接沖高,所以研發團隊對堆內存的分配需要時刻注意;

  • 避免不必要的堆內存開銷。UWA測評報告中將項目運行過程中堆內存分配Top10函數進行羅列,限於篇幅,我們不再此處進行一一贅述,研發團隊可以直接查看之前一篇的內存優化相關文章。

資源冗余

在內存管理方面,還有一個大家必須關注的話題——資源冗余。在我們測評過的大量項目中,95%以上的項目均存在不同程度的資源冗余情況。所謂“資源冗余”,是指在某一時刻內存中存在兩份甚至多份同樣的資源。導致這種情況的出現主要有兩種原因:

一、AssetBundle打包機制出現問題

同一份資源被打入到多份AssetBundle文件中。舉個例子,同一張紋理被不同的NPC所使用,同時每個NPC被制作成獨立的AssetBundle文件,那么在沒有針對紋理進行依賴打包的前提下,就會出現該張紋理出現在不同的NPC AssetBundle文件中。當這些AssetBundle先后被加載到內存后,內存中即會出現紋理資源冗余的情況。對此,我們建議研發團隊在發現資源冗余問題后,對相關AssetBundle的制作流程一定要進行檢查。

同時,我們在UWA測評中為每個資源引入了一個衡量指標——“數量峰值”。它指的是同一資源在同一幀中出現的最大數量。如果大於1,則說明該資源很可能存在 “冗余資源”。大家可以通過這一列進行排序,即可立即查看項目中的資源冗余情況。

 

 

二、資源的實例化所致

在Unity引擎中,當我們修改了一些特定GameObject的資源屬性時,引擎會為該GameObject自動實例化一份資源供其使用,比如Material、Mesh等。以Material為例,我們在研發時經常會有這樣的做法:在角色被攻擊時,改變其Material中的屬性來得到特定的受擊效果。這種做法則會導致引擎為特定的GameObject重新實例化一個Material,后綴會加上(instance)字樣。其本身沒有特別大的問題,但是當有改變Material屬性需求的GameObject越來越多時(比如ARPG、MMORPG、MOBA等游戲類型),其內存中的冗余數量則會大量增長。如下圖所示,隨着游戲的進行,實例化的Material資源會增加到333個。雖然Material的內存占用不大,但是過多的冗余資源卻為Resources.UnloadUnusedAssets API的調用效率增加了相當大的壓力。

 

一般情況下,資源屬性的改變情況都是固定的,並非隨機出現。比如,假設GameObject受到攻擊時,其Material屬性改變隨攻擊類型的不同而有三種不同的參數設置。那么,對於這種需求,我們建議你直接制作三種不同的Material,在Runtime情況下通過代碼直接替換對應GameObject的Material,而非改變其Material的屬性。這樣,你會發現,成百上千的instance Material在內存中消失了,取而代之的,則是這三個不同的Material資源。其中的益處,對於能夠閱讀到這里的你來說,應該已經不需要我多說了。:)

以上則是我們在內存優化工作中的經驗和心得,希望它對你的項目研發有所幫助。優化永遠沒有統一的標准方案,只有最適合你項目的方案,希望大家可以活學活用,不要放過任何一處讓你感覺“不對勁”的地方。最后提醒大家——“勿以善小而不為,勿以惡小而為之”,共勉!

轉載自:https://zhuanlan.zhihu.com/p/21913837 來源:知乎

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM