我們都知道托管代碼剝離是構建游戲作品過程中的關鍵步驟,。該步驟有助于減小應用程序二進制文件的大小。它通過移除未使用的代碼來實現,。
通過刪除代碼,用戶可以確保這些代碼不會被編譯或包含在最終的構建中,。雖然這會稍微減少使用IL2CPP后端運行項目的內存使用,,但是在運行時,在較高的托管代碼剝離級別下,,總會有丟失類型和方法的風險,。
在整個構建過程中,經常有一些代碼是無效的,,這些無效代碼會被剝離,。手動將所需的程序集添加到link.xml文件不是防止它們被移除的最簡單方法。在本文中將為大家介紹這些技巧和最佳的應用方法,,以便大家有效改進托管代碼剝離工作流,。
使用Unity鏈接器剝離托管代碼
當我們使用IL2CPP腳本后端時,刪除未使用的代碼尤其重要,。Unity鏈接器——Mono IL linker將執(zhí)行靜態(tài)分析以剝離托管代碼,。
Unity支持IL2CPP低、中,、高三個級別的托管代碼剝離,。托管代碼剝離指導手冊解釋了代碼剝離過程是如何工作的,哪些因素剝離了某些代碼,,以及剝離級別如何彼此不同,。簡而言之:代碼剝離級別越高,鏈接器就越難找到并移除未使用的代碼,。因此我們可以在項目的“播放器設置”中修改“受管理的剝離級別”以快速找到那些被視為未使用的代碼,。
鏈接器利用靜態(tài)分析來識別未使用的代碼,,當某個對象的類型只在運行時定義時,靜態(tài)分析不能覆蓋所有情況,。這些案例會導致虛假的積極性結果,。雖然編譯時可能沒有任何對類或方法的引用,但運行時代碼的某些部分仍然需要該類或方法,。在這種情況下,,使用反射是一個很好的例子。
雖然這是一種有效且常用的代碼類型,,但鏈接器不知道MyAssembly,、MyType和MyMethod是否在運行時實際使用。這可能會導致它們被剝離,,進而導致運行時錯誤,。
使用依賴注入框架(如Zenject)或序列化庫(如Newtonsoft)的開發(fā)人員必須意識到假陽性代碼剝離是可能的。以下是一些最常見的解決方法:
鏈接器可以識別許多屬性,,并允許用戶在無法識別它們時對依賴項進行注釋,。因此,用戶可以添加屬性不應被分離的程序集,、類和方法,。
link.xml文件是一個針對每個項目的列表,記錄了保留程序集,、類型和其他代碼,,用戶可以手動添加所需的程序集、類型和方法到link.xml,,或者使用UnityEditor APIgenerated additionallinkxmlfile在構建過程中生成link.xml文件,。
可尋址包也利用了LinkxmlGenerator??蓪ぶ钒臉嫿_本會檢查組中的資產列表,,并將資產使用的類型添加到link.xml文件中。它還通過運行時的反射在內部添加了可尋址包使用的類型,。
Unity支持位于“資源”文件夾或其子文件夾中的多個link.xml文件,。在構建過程中,鏈接器會合并和計算多個link.xml文件的條目,。
Unity 2020 LTS版中托管代碼剝離有什么新功能
使用屬性可能需要一些手動操作,。但是如果項目已經在Unity 2020 LTS中,我們可以使用許多新的托管代碼剝離注釋屬性來輕松,、精確地在代碼剝離過程中標記不該刪除的程序集與類型,。以下是一些方法:
Required AttributeUsagesAttribute:標記屬性類型時,該類型的所有自定義屬性也將被標記,,從而減少在高剝離級別工作時的復雜性,。
RequireDerivedAttribute:標記類型時,,從該類型派生的所有類型都將被標記。
RequiredInterfaceAttribute:標記類型時,,將標記指定類型的所有接口,。
RequiredMemberAttribute:標記類型時,其所有帶有[RequiredMember]的類型都將被標記,。這使得代碼剝離更加精確,,因為它將阻止聲明類型變得不可剝離。但是請注意,,如果不使用類型本身,,盡管標記了[RequiredMember]屬性,Members也將被剝離,。
RequireImplementorsAttribute:標記接口類型時,,將標記該接口的所有類型。因此沒有必要標記每個接口,。但是如果接口沒有在代碼庫中的任何地方運行,,它仍然會被移除,盡管它已經被標記為[RequiresImplementors]屬性,。
在Unity 2020.1和2020.2中,,該工具已經收到了與Mono IL?Linker匹配的API更新。它現在可以檢測到一些簡單的反射模式,,這意味著如果您已經升級到Unity 2020 LTS,那么使用link.xml文件的理由就更少了,。
作為Unity 2021年目標的一部分,,即讓創(chuàng)作者更容易向測試人員和玩家交付高質量的作品,Unity一直專注于改進代碼剝離工作流,。更具體地說,,在2021.2版本中Unity添加了一個名為“最小”的新托管剝離級別。這將是IL2CPP后端的默認設置,。