unity文檔翻譯 2021.3 Unity architecture->ScriptingUnity architectureOverview of .NET in Unity
https://docs.unity3d.com/Manual/overview-of-dot-net-in-unity.html
Overview of .NET in Unity (Unity中.Net的OverView)
Unity uses the open-source .NET platform to ensure that applications you make with Unity can run on a wide variety of different hardware configurations. The .NET platform supports a range of languages and API libraries.
(Unity使用open-source .Net platform ,確保多平臺運行。)
Scripting backends 腳本后端 腳本運行模式
Unity has two scripting backends; Mono, and IL2CPP (Intermediate Language To C++), each of which uses a different compilation technique (兩種腳本運行模式Mono和IL2CPP):
- Mono uses just-in-time (JIT) compilation and compiles code on demand at runtime. (Mono 使用JIT編譯器,運行時按需編譯code )
- IL2CPP uses ahead-of-time (AOT) compilation and compiles your entire application before it runs.(AOT 在運行application前預編譯)
The benefit of using a JIT-based scripting backend is that the compilation time is typically much faster than AOT.(JIT編譯器通常編譯速度比較快)
By default, Unity uses the Mono backend on platforms that support Mono. When you build a player for your application, you can choose which scripting backend to use. To do this through the Editor, go to Edit > Project Settings > Player, open the Other Settings panel, then click on the Scripting Backend dropdown and select which backend you want. For more information, see Scripting backends . (默認使用Mono方式)
.
Managed code stripping 托管代碼的剝離
When you build an application, Unity compiles and then searches the assemblies (.DLLs) in your project to detect and remove unused code. This process of stripping code reduces the final binary size of your build, but increases build time.
build 的時候, 當unity編譯后,會去檢測項目中的 程序集DLLs并且移除無用的代碼。此代碼剝離流程會減少最后binary的大小。但是增加了build時長。
Code stripping is disabled by default when you use Mono but code stripping can’t be disabled for IL2CPP. You can control how much code Unity strips with the Managed Stripping Level property.
在Mono模式下code striping是禁止的。 在IL2CPP下開啟,并且用戶可以設置stripping的等級。
As you increase the Managed Stripping Level, Unity removes more code. This increases the risk that Unity might remove code that your application relies on, especially if you use reflection or generate code at runtime.
stripping等級越高,unity會移除更多unused的代碼。 不過這也增加了風險:有概率移除 application 可能需要使用到的代碼。尤其是在runtime下使用反射或者代碼生成。
You can use annotations on certain elements of your code to prevent Unity from stripping it. For more information, see Managed Code Stripping.
stripping詳情請看鏈接
Garbage collection 垃圾回收
Unity uses the Boehm garbage collector for both the Mono and IL2CPP backends. Unity uses the Incremental mode by default. You can disable the Incremental mode to use stop-the-world garbage collection, although Unity recommends the Incremental mode.
使用Boehm garbage collector 垃圾回收方式。默認使用增量模式。盡管unity建議使用Incremental mode,我們也可以關閉Incremental mode,使用stop-the-world模式。
To toggle between Incremental mode and stop-the-world, go to Edit > Project Settings > Player, open the Other Settings panel and click on the Use incremental GC checkbox. In Incremental mode, Unity’s garbage collector only runs for a limited period of time and doesn’t necessarily collect all objects in one pass. This spreads the time it takes to collect objects over multiple frames and reduces stuttering and CPU spikes. For more information, see Managed memory.
In Incremental mode,unity垃圾回收只運行有限的時間段,并不需要一次性收集所有對象的信息。這樣把垃圾回收分散在多幀,可以減少卡頓和CPU的峰值。詳細查看鏈接
To check the number of allocations and possible CPU spikes in your application, use the Unity Profiler. You can also use the GarbageCollector API to completely disable garbage collection in Players. When the collector is disabled, be careful to avoid allocating excess memory.
Unity Profiler可以進行性能檢測。 GarbageCollector API可以控制GC的開啟。
.NET system libraries .NET 系統庫
Unity supports many platforms and might use different scripting backends depending on the platform. The .NET system libraries require platform-specific implementations to work correctly in some cases. While Unity tries its best to support as much of the .NET ecosystem as possible, there are some exceptions to parts of the .NET system libraries that Unity explicitly doesn’t support.
Unity明確不支持some exceptions
Unity makes no performance or allocation guarantees for the .NET system libraries across Unity versions. Generally, Unity doesn’t fix any performance regressions in the .NET system libraries.
如果.Net system lib 跨Unity版本,Unity不保證性能和內存分配。通常Unity不會修復.NET的性能問題。
Unity doesn’t support the System.Drawing library and it isn’t guaranteed to work on all platforms.
不支持 System.Drawing library
The JIT compilation that the Mono scripting backend uses enables you to emit dynamic C#/.NET Intermediate Language (IL) code generation during the runtime of your application. The AOT compilation
that the IL2CPP scripting backend uses doesn’t support dynamic code generation.
Mono模式下可以runtime生成IL代碼。IL2CPP模式下不支持dynamic code generation
This is important to consider when you use third-party libraries, because they might have different code paths for JIT and AOT, or they might use code paths that rely on dynamically generated code. For more information on how to generate code at runtime, see Microsoft’s ModuleBuilder documentation.
使用第三方庫的時候需要注意,第三方庫對JIT和AOT的支持,以及第三方庫是否依賴dynamic generate code?
Although Unity supports multiple .NET API profiles, you should use the .NET Standard API Compatibility Level for all new projects for the following reasons:
最好使用 .NET Standard 原因:
- .NET Standard is a smaller API surface and so has a smaller implementation. This reduces the size of your final executable file. 小 內存少
- .NET Standard has better cross-platform support, so your code is more likely to work across all platforms. 跨平臺支持好
- All .NET runtimes support .NET Standard, so your code works across more VM/runtime environments (for example, .NET Framework. .NET Core, Xamarin, Unity) when you use .NET Standard. .NET都在Net Standard的標準內
- .NET Standard moves more errors to compile time. A number of APIs in .NET Framework are available at compile time, but have implementations on some platforms that throw an exception at runtime. 編譯期報錯更明顯
Other profiles can be useful if, for example, you need to provide support for an older existing application. To change the Api Compatibility Level setting, go to Edit > Project Settings > Player. Under the Other Settings heading, set the Api Compatibility Level to the desired setting.
For more information, see .NET Profile Support.
Using third-party .NET libraries
You should only use third-party .NET libraries that have been extensively tested on a wide range of Unity configurations and platforms.
The performance characteristics of JIT and AOT code paths in third-party libraries might be significantly different. AOT generally reduces startup times and is suited to larger applications for this reason but increases the binary file size to accommodate the compiled code. AOT also takes longer to build during development.
AOT減少啟動時間并且適用于大型應用,但是會增大編譯后代碼二進制文件大小。AOT打包比較慢。
JIT adjusts at runtime based on the platform it’s running on, which can increase running performance at the cost of a potentially longer application startup time. As such, you should profile your application in both the Editor, and on your target platform. For more information, see Profiler overview.
JIT在運行時根據運行的平臺進行調整,這可以提高運行性能。 而且會增增加應用的啟動時間。
You should profile the usage of your .NET system libraries on all target platforms because their performance characteristics might vary depending on the scripting backends, .NET versions, and profiles you use.
When you review a third-party library, consider the following areas:
- Compatibility: Third-party libraries might not be compatible with some Unity platforms and scripting backends. 平臺支持問題
- Performance: Third-party libraries might have vastly different performance characteristics in Unity compared to other .NET runtimes. 性能可能有問題
- AOT binary size: Third-party libraries might increase AOT binary size significantly because of the number of dependencies the library uses. (AOT下二進制大小可能會爆炸是增長)
C# reflection overhead
Mono and IL2CPP internally cache all C# reflection (System.Reflection) objects and by design, Unity doesn’t garbage collect them. The result of this behavior is that the garbage collector continuously scans the cached C# reflection objects during the lifetime of your application, which causes unnecessary and potentially significant garbage collector overhead.
Mono和IL2CPP內部緩存所有c#反射(System.Reflection)對象,Unity不會對它們進行垃圾收集。垃圾收集器在應用程序的生命周期中不斷掃描緩存的c#反射對象,這將導致不必要的和潛在的重大垃圾收集器開銷。
To minimize the garbage collector overhead, avoid methods such as Assembly.GetTypes and Type.GetMethods() in your application, which create a lot of C# reflection objects at runtime. Instead, you should scan assemblies in the Editor for the required data and serialize and/or codegen it for use at runtime.
要最大程度減少垃圾回收器開銷,請避免使用諸如 Assembly.GetTypes 和 Type.GetMethods() 等方法,這些方法會在運行時創建許多 C# 反射對象。而是應該在編輯器中掃描程序集以獲取所需數據,并進行序列化和/或代碼生成以在運行時使用
UnityEngine.Object special behavior
UnityEngine.Object is a special type of C# object in Unity, because it’s linked to a native C++ counterpart object. For example, when you use a Camera component, Unity stores the state of the object on the object’s native C++ counterpart, not on the C# object itself.
UnityEngine.Object 是一種特殊類型的C#對象。會link到一個原生的C++對象。例如當你使用相機組件時,Unity將對象的狀態存儲在對象的原生c++對應對象上,而不是在c#對象本身上

Unity doesn’t currently support the use of the C# WeakReference class with instances of UnityEngine.Object. For this reason, you shouldn’t use a WeakReference to reference a loaded asset. See Microsoft’s WeakReference documentation for more information on the WeakReference class.
Unity目前不支持在UnityEngine的實例中使用c# WeakReference類
Unity C# and Unity C++ share UnityEngine Objects
When you use a method such as Object.Destroy or Object.DestroyImmediate to destroy a UnityEngine.Object derived object, Unity destroys (unloads) the native counter object. You can’t destroy the C# object with an explicit call, because the garbage collector manages the memory. Once there are no longer any references to the managed object, the garbage collector collects and destroys it.
使用Object.Destroy or Object.DestroyImmediate 時,Unity unload原生counter 對象,這時候并不是真正的銷毀,只是一種標記手段。GC去管理真正的銷毀。
If your application tries to access a destroyed UnityEngine.Object again, Unity recreates the native counterpart object for most types. Two exceptions to this recreation behavior are MonoBehaviour and ScriptableObject: Unity never reloads them once they have been destroyed.
當訪問被Destroyed的UnityEngine.Object時,Unity會重建 原生C++對象。除了 MonoBehaviour and ScriptableObject
MonoBehaviour and ScriptableObject override the equality (==) and inequality (!=) operators. If you compare a destroyed MonoBehaviour or ScriptableObject against null, the operators return true when the managed object still exists and hasn’t yet been garbage collected.
MonoBehaviour and ScriptableObject的 ==和!=被重寫。當這兩種類型的對象被destroyed后,被托管的對象實際內存還是存在的,還沒有被垃圾回收,但是已經被標記為為“假空”了。所以使用==null會return true。
Because you can’t overload the ?? and ?. operators, they aren’t compatible with objects that derive from UnityEngine.Object. The operators don’t return the same results as the equality and inequality operators when you use them on a destroyed MonoBehaviour or ScriptableObject while the managed object still exists.
??和?.沒有被重寫 返回的結果不是我們想要的 因為當前托管對象還在內存里。
下面的鏈接解釋了unity doc里(上面標記黃色的 :“Unity會重建 原生C++對象”)的意思:
https://answers.unity.com/questions/1705335/how-can-throw-missing-reference-exception-this-gam.html
However we have the Destroy method to destroy any objects derived from UnityEngine.Object. What the method does is actually destroying the object on the native side and mark the managed wrapper object as "being destroyed".
UnityEngine.Object會確切的銷毀 原生對象,并且把C#端托管對象標記為 “being destory”。 如果沒理解錯,UnityEngine.Object真正的內存在C++端顯示管理,托管C#端只是一個標記object
Limitations of async and await tasks aysnc和await的局限
The Unity API isn’t thread safe and therefore, you should only use async and await tasks from inside the UnitySynchronizationContext. Async tasks often allocate objects when invoked, which might cause performance issues if you overuse them.
Unity API不是線程安全的。你應該只使用UnitySynchronizationContext中的async和await tasks。異步任務通常在調用時分配對象,如果過度使用,可能會導致性能問題。
Unity overwrites the default SynchronizationContext with a custom UnitySynchronizationContext and runs all the tasks on the main thread in both Edit and Play modes by default. To use async tasks, you must manually create and handle your own threads with the Task.Run API, and use the default SynchronizationContext instead of the Unity version.
Unity用自定義的UnitySynchronizationContext重寫默認的SynchronizationContext,并在默認的編輯和播放模式下運行主線程上的所有任務。要使用async tasks,你必須使用Task.Run 手動創建和處理自己的線程 ,并使用默認的SynchronizationContext而不是Unity版本。
Unity doesn’t automatically stop async tasks that run on managed threads when you exit Play mode. To listen for enter and exit Play mode events to stop the tasks manually, use EditorApplication.playModeStateChanged. If you take this approach, most of the Unity scripting APIs aren’t available to use unless you migrate the context back to the UnitySynchronizationContext.
當你退出游戲模式時,Unity不會自動停止在托管線程上運行的異步任務。要監聽進入和退出播放模式事件以手動停止任務,請使用EditorApplication.playModeStateChanged。如果你采用這種方法,大多數Unity腳本api都無法使用,除非你將context移回UnitySynchronizationContext。
For performance reasons, Unity doesn’t perform checks for multithreaded behavior in non-development builds and doesn’t display this error in live builds. This means that while Unity doesn’t prevent execution of multithreaded code on live builds, random crashes and other unpredictable errors are likely if you do use multiple threads.
出于性能原因,Unity不會在非開發構建中執行多線程行為檢查,也不會在實時構建中顯示此錯誤。這意味著雖然Unity不會阻止在實時構建中執行多線程代碼,如果你使用多線程,則可能會出現隨機崩潰和其他不可預測的錯誤。
For this reason, you shouldn’t use your own multithreading and instead use Unity’s job system. The job system uses multiple threads safely to execute jobs in parallel and achieve the performance benefits of multithreading. For more information, see Job system overview.
出于這個原因,你不應該使用自己的多線程,而是使用Unity’s job system。The job system 使用多線程安全地并行執行作業,實現了多線程的性能優勢。有關更多信息

浙公網安備 33010602011771號