當前位置:
首頁 > 最新 > 如何使用靜態分析優化Unity代碼?

如何使用靜態分析優化Unity代碼?

在Unity開發者大會上聽了一個介紹對Unity腳本做靜態分析的演講,感覺非常有用,於是做了一些嘗試。大概就是提供了一個基於微軟Roslyn插件UnityEngineAnalyzer可以對Unity的代碼做靜態分析,找到一些代碼隱患和一些可能存在的性能問題。插件可以單獨運行,也可以導入VS做為一個插件,它取代部分人工的ProjectReview,並可集成到CI系統(持續集成)做自動化檢測。

什麼是靜態代碼分析

簡而言之就是指在不運行代碼的情況下,通過詞法分析,語法分析等技術對代碼做掃描和解析,驗證代碼是否滿足規範,是否有隱患,是否可靠可維護等。例如比較著名的Lint可以檢測出可能的空指針,拼寫錯誤,除0等等。VS,還有VS的插件Resharper也帶有靜態代碼分析的功能。和一般的插件不同,UnityEngineAnalyzer可以分析一些Unity特有的一些性能和問題隱患,也支持自定義添加規則。

什麼是Roslyn

Roslyn 是微軟公司開源的 .NET 編譯器。編譯器支持 C# 和 Visual Basic 代碼編譯,並提供豐富的代碼分析 API。這是一個更為開放式的編譯器,與以往不透明的編譯過程不同,開發者可以在編譯過程中訪問和分析編譯數據。根據提供的API可以進行大量用戶自定義的擴展。通過使用Roslyn提供的API,在您鍵入代碼時,甚至在您完成一行之前,它們就能生成警告,不需要等到生成代碼時才找出您所犯的錯誤。分析器還可以通過新的 Visual Studio 燈泡圖標提示來顯現自動代碼修復方案,讓您立即清理代碼。

為什麼需要靜態代碼分析

提早發現代碼中的BUG,避免將BUG帶到生產環境

極大的提高軟體質量,以及可維護性

統一代碼規範、提高可讀性,減少新加入成員的熟悉時間

加速個人和團隊的成長,知識和經驗的積累

節約有限的開發時間

避免人工檢查的遺漏,不可能記住所有優化點也不能保證不遺漏

可以內建到CI系統(持續集成)

規範的項目一般會有代碼審核,而代碼審核分為人工審查和工具審查。人工審查方面目前每天會有代碼Review,每個版本會做ProjectReview。但是人都會有疏漏,使用自動化的工具進行補充可以避免人工檢查的漏洞和節省大量時間。

UnityEngineAnalyzer的優點

可以發現Unity特有的一些潛在問題,例如代碼規範,性能問題

可以作為VS插件使用,也可以作為獨立的程序單獨執行

可以通過ComandLine執行

可以生成HTML報告

多平台支持

以下是他們官網的介紹:UnityEngineAnalyzer分析器是一套基於Roslyn分析程序,旨在檢測Unity3D C#代碼中的常見問題。Unity3D讓我們很容易做跨平台遊戲,但是有一些隱藏的規則例如性能和AOT等,會影響到程序的體驗和測試等。我們希望這些問題能在編譯之前被發現。

UnityEngineAnalyzer的檢查項

不允許直接Tag的比較,使用CompareTag代替直接比較減少GC;

不允許在Update中調用Find;

不允許有空的MonoBehaviour方法,例如Update,FixedUpdate,LateUpdate等;

不允許使用OnGUI,OnGUI會導致GC;

不允許使用Coroutine避免產生GC,這個目前使用的5.5.1版本已經修復不需要了;

不允許使用Foreach避免產生GC,這個目前使用的5.5.1版本已經修復不需要了;

string方法

Remoting(AOT),EmitCalls(AOT),GetType(AOT)

對IL2CPP,使用去虛擬化可以提升部分虛函數調用的開銷 http://gad.qq.com/article/detail/7168288

…….

例子如下:

UnityEngineAnalyzer的使用

命令行模式

1. 到 https://github.com/vad710/UnityEngineAnalyzer 下載最新版本,然後解壓縮,編譯。UnityEngineAnalyzer.CLIin目錄下得到可執行文件UnityEngineAnalyzer.CLI.exe。

2. 打開命令提示符或Powershell窗口。

3. 運行UnityEngineAnalyzer.CLI.exe

。例如:> UnityEngineAnalyzer.CLI.exe C:CodeMyGame.CSharp.csproj

4. 觀察分析結果。

5. 在項目文件相同位置,會生成report.json和UnityReport.html報告。

上圖是我們項目的分析報告。需要注意的是html需要用FireFox瀏覽器打開,json可以直接瀏覽。原始工程的exe在執行的時候會報一些異常需要修改一下代碼,主力工程不需要。命令行模式設置可以通過選擇項目-〉右鍵-〉屬性;調試-〉命令行參數。然後在命令行參數裡面輸入命令行參數調試運行。

NuGet打包

有兩種方式可以製作插件集成到VS工程中,一個就是以NuGet package的方式。因為在網上已經有編譯好的NuGet包,我只嘗試了直接使用並沒有編譯本地的的NuGet。安裝步驟如下:

1. 使用VS2015打開目標工程

2. 選擇Tools->NuGet Package Manager->Manage NuGet Package for solution,如下圖:

3. 在Browse頁面搜索UntiyEngineAnalyzer並選中

4. 在右側屬性面板中勾選你希望分析的項目點擊Install。(注意源的版本比較老只能添加一個工程)

VSIX擴展包

另一種方式是編譯成VSIX插件,安裝到VS中對IDE下所有項目進行分析。只要編譯UnityEngineAnalyzer.Vsix工程在bin中雙擊UnityEngineAnalyzer.Vsix.vsix安裝即可。安裝完畢可以在Tools/Extensions and Updates里看到,如下圖:

重啟VS之後在Error List就可以看到用戶自定義的Unity特有的Wanrings了,如下圖:

因為NuGet源上的版本非常老了而且使用沒有VSIX方便,所以最終使用了VSIX的方式,給其他人提供了VSIX的插件。

UnityEngineAnalyzer的擴展

我們當然可以對分析器進行擴展和修改。例如新版本的Unity不需要對Foreach等做限制,另外可以添加項目組自己的代碼規範,代碼風格,特定設置等。

安裝Visual Studio 2015或者更高版本

安裝Roslyn_SDK https://marketplace.visualstudio.com/items?itemName=VisualStudioProductTeam.NETCompilerPlatformSDK

解決方案中的工程如下:

UnityEngineAnalyzer:這是主項目,構建包含診斷和代碼修補程序的分析器 DLL

UnityEngineAnalyzer.CLI:這是可執行的exe

UnityEngineAnalyzer.Test:這是單元測試項目,有一些測試用例便於調試

UnityEngineAnalyzer.Vsix:這是製作用於VS的插件的項目,也是把dll綁定到VS中

安裝完SDK之後VS有相應的模版可以創建工程,這裡沒有這個需求只是在源工程上修改。

如果通過模版創建會默認生成DiagnosticAnalyzer代碼,這裡每條分析都一個派生類繼承自DiagnosticAnalyzer。例如DoNotUseOnGUIAnalyzer。

在DiagnosticIDs這個文件里可以自定義一些用戶自己希望使用的警告標籤,例如DoNotUseOnGUI = "UEA0001"

AnalyzerTestFixture是測試用例的基類。

通過設置UnityEngineAnalyzer.Vsix啟動啟動,按F5啟動可以啟動一個VS副本用來調試。這和安裝完VS第一次啟動一樣,還需要設置一些參數風格等。如下圖右邊的VS通過調試模式啟動左邊的VS,這是在打斷點調試。

如下圖可以看到副本的VS中警告部分會有綠色下劃線,下方會有warning的標籤,原因提示等,雙擊也可以調到有問題的代碼的地方。

然後我們看一下如何進行擴展。首先第一步繼承Initialize函數,這是分析器的入口函數,通過註冊一個回調來進行診斷。例如context.RegisterSymbolAction(AnalyzeSymbol, SymbolKind.Method);其中AnalyzeSymbol是要實現的檢查的回調函數,SymbolKind.Method是檢測類型,後面再可視化視圖中可以看到節點類型。每次啟動的時候會調用一次Initialize。

當每次在VS中鍵入代碼的時候,都會調用註冊的回調函數AnalyzeSymbol(用戶可以自己定義)。當檢測發現問題的時候則調用context.ReportDiagnostic(diagnostic)方法,拋出一個警告。參數diagnostic可以設置警告的標籤,警告的內容,行號,類名等等。用戶可以通過context獲取節點的一些信息,例如函數名是否是OnGUI,如果不是則返回。如果是繼續判斷該函數的類是否是Unity的MonoBehaviour類的派生類。代碼如下:

DiagnosticDescriptors是一個靜態類,它的作用就是創建一些靜態的DiagnosticDescriptor,用來設置標籤和內容等,字元串等放在ResourceManager中,然後添加到ImmutableArray SupportedDiagnostics。

選擇View->Other Windows->SyntaxTree,可以打開語法分析窗口,將滑鼠放在代碼的某一行上可以得到語法樹的可視化信息。如下圖:

通過在編輯器中選擇代碼,您可以看到樹中的相關節點,反之亦然。還可以在語法樹中右鍵單擊「View Directed Syntax Graphic」生成一個圖,可視化所選節點的樹結構,可以看到語法令牌、各個詞、數字和符號等。例如Initialize函數,如圖 4 中所示。

如果右鍵選擇「View Symbol」,可以在下面的屬性網格將顯示所調用方法的方法符號信息,可以看到Initialize的調用是UnityEngineAnalyzer.AOT.TypeGetTypeAnalyzer.Initialize(Microsoft.CodeAnalysis.Diagnostics.AnalysisContext),如下圖:

打開DoNotUseOnGUIResources.resx文件,可以設置在錯誤列表中向用戶顯示標題,描述等。使用者還可以使用 #pragma 指令禁止該診斷的某個測試。,如下圖:

還可以通過設置defaultSeverity:http://DiagnosticSeverity.Info設置將要生成的診斷的嚴重程度,例如Info,Warning,Error等。如果 改為Error在VS中則會中斷編譯。另外也可以定義是否在默認情況下關閉或打開,可以選擇加入部分或者全部規則。例如:

SupportedDiagnostics 屬性可以添加單個或多個診斷。一般情況一個分析器應該只生成一種診斷,但有的時候一個分析會區分在不同情況下拋出不同的診斷,例如DoNotUseFindMethodsInUpdate和DoNotUseFindMethodsInUpdateRecursive。

除了可以發現編碼中的錯誤,另外還可以編寫代碼來提供修改代碼的方案。這個暫時還沒有嘗試。

附上其他的一些Register的方法。

UnityEngineAnalyzer的總結

靜態代碼分析不能代替性能分析和Review等人工檢查,但可以節省大量時間和將部分過程自動化流程化。

可以從性能分析中得到優化點不斷添加到新的分析器中。

只能優化代碼。

可根據需求或者Unity版本升級,隨時修改Analyzer。

配合項目的0Error和0warning計劃極大程度提高代碼穩定性。

Mac下還不支持,還不能集成到Unity編輯器中。

不同平台制定不同的優化策略。例如IL2cpp的反虛擬化優化,減少虛函數的調用開銷。

如何獲得UnityEngineAnalyzer

當前活躍項目: https://github.com/vad710/UnityEngineAnalyzer

原始項目: https://github.com/meng-hui/UnityEngineAnalyzer

其他項目:https://bitbucket.org/kzoabi/unity3d-gendarme-plugin


喜歡這篇文章嗎?立刻分享出去讓更多人知道吧!

本站內容充實豐富,博大精深,小編精選每日熱門資訊,隨時更新,點擊「搶先收到最新資訊」瀏覽吧!

TAG: |