Assets, Resources and AssetBundles(2)翻译
2.Assets, Objects and serialization
This chapter covers the deep internals of Unity's serialization system and how Unity maintains robust references between different Objects, both in the Unity Editor and at runtime. It also discusses the technical distinctions between Objects and Assets. The topics covered here are fundamental to understanding how to efficiently load and unload Assets in Unity. Proper Asset management is crucial to keeping loading times short and memory usage low.
这一章涵盖了Unity's serialization system的深层内部内容,以及Unity如何在Unity编辑器和运行时中维护不同Objects之间的健壮引用。它还讨论了Objects 和 Assets之间的技术区别。这里涉及的主题对于理解如何在Unity中有效地加载和卸载 Assets是非常基本的。正确的Asset management对于保持较短的加载时间和较低的内存使用量至关重要。
2.1. Inside Assets and Objects
To understand how to properly manage data in Unity, it is important to understand how Unity identifies and serializes data. The first key point is the distinction between Assets and UnityEngine.Objects.
为了理解如何正确地管理Unity中的data,理解Unity如何识别和序列化数据是很重要的。第一个关键点是Assets 和UnityEngine.Objects之间的区别。
An Asset is a file on disk, stored in the Assets folder of a Unity project. Textures, 3D models, or audio clips are common types of Assets. Some Assets contain data in formats native to Unity, such as materials. Other Assets need to be processed into native formats, such as FBX files.
Asset 是磁盘上的一个文件,存储在Unity项目的Assets 文件夹中。Textures、3D模型或audio clips 是常见的Assets类型。有些Assets包含的data对在格式对Unity来说是原生(native)的,比如materials。其他资产需要处理为原生格式,比如FBX文件。
A UnityEngine.Object, or Object with a capitalized 'O', is a set of serialized data collectively describing a specific instance of a resource. This can be any type of resource which the Unity Engine uses, such as a mesh, sprite, AudioClip or AnimationClip. All Objects are subclasses of the UnityEngine.Object base class.
UnityEngine.Object(或大写'O'的Object)是一组序列化的数据,共同描述资源的特定实例(instance of a resource)。这可以是Unity引擎使用的任何类型的资源()resource ,如mesh,sprite, AudioClip或AnimationClip。所有Objects 都是UnityEngine.Object基类的子类。
While most Object types are built-in, there are two special types.
虽然大多数对象类型是内置的,但有两种特殊类型
-
A ScriptableObject provides a convenient system for developers to define their own data types. These types can be natively serialized and deserialized by Unity, and manipulated in the Unity Editor's Inspector window.
- ScriptableObject为开发人员提供了一个方便的系统 定义自己的数据类型。这些类型可以被Unity 原生的serialized and deserialized,在Unity Editor's Inspector window中操作。
-
A MonoBehaviour provides a wrapper that links to a MonoScript. A MonoScript is an internal data type that Unity uses to hold a reference to a specific scripting class within a specific assembly and namespace. The MonoScript does not contain any actual executable code.
- MonoBehaviour提供了一个链接到MonoScript的包装器。一个
MonoScript是一个Unity用来保存特定程序集(assembly)和命名空间中到特定脚本类(specific scripting class )的内部数据类型。MonoScript不包含任何实际的可执行代码。
There is a one-to-many relationship between Assets and Objects; that is, any given Asset file contains one or more Objects.
Assets 和Objects之间存在一对多关系;也就是说,任何给定的Assets文件都包含一个或多个Objects。
2.2. Inter-Object references
All UnityEngine.Objects can have references to other UnityEngine.Objects. These other Objects may reside within the same Asset file, or may be imported from other Asset files. For example, a material Object usually has one or more references to texture Objects. These texture Objects are generally imported from one or more texture Asset files (such as PNGs or JPGs).
所有UnityEngine.Objects可以引用其他UnityEngine.Objects。这些其他对象可以驻留在相同的Asset 文件中,或者可以从其他资产文件中导入。例如,一个材质对象通常有一个或多个对纹理对象的引用。这些纹理对象通常从一个或多个纹理资产文件(如png或jpg)导入。
When serialized, these references consist of two separate pieces of data: a File GUID and a Local ID. The File GUID identifies the Asset file where the target resource is stored. A locally unique Local ID identifies each Object within an Asset file because an Asset file may contain multiple Objects. (Note: AA Local ID is unique from all the other Local IDs for the same Asset file.)
当序列化时,这些引用由两个独立的数据组成:文件GUID和本地ID。文件GUID标识存储目标资源(target resource )的Asset文件。本地唯一的Local ID标识Asset文件中的每个对象(Object ),因为一个Asset文件中可能包含多个对象(Objects)。(注意:对于同一Assets文件,AA本地ID与所有其他本地ID是唯一的。)
File GUIDs are stored in .meta files. These .meta files are generated when Unity first imports an Asset, and are stored in the same directory as the Asset.
文件GUIDs 存储在.meta文件中。这些.meta文件是在Unity第一次导入Asset时生成的,并且存储在与Asset相同的目录中。
The above identification and referencing system can be seen in a text editor: create a fresh Unity project and change its Editor Settings to expose Visible Meta Files and to serialize Assets as text. Create a material and import a texture into the project. Assign the material to a cube in the scene and save the scene.
上面的标识(identification )和引用系统(referencing system)可以在一个文本编辑器中看到:创建一个新的Unity项目,并改变它的编辑器设置(Editor Settings),以显示Visible Meta Files并序列化Assets为文本。创建一个材质并导入纹理到项目中。将材质指定给场景中的一个立方体,然后保存场景。
【注:设置过程为
①Project Setting->Editor->Version Control->Mode-Visible Meta Files
②Project Setting->Editor->Assets Serialization->Mode-Force Text】
Using a text editor, open the .meta file associated with the material. A line labeled "guid" will appear near the top of the file. This line defines the material Asset's File GUID. To find the Local ID, open the material file in a text editor. The material Object's definition will look like this:
使用文本编辑器,打开与该材料关联的.meta文件。标签为“guid”的行将出现在文件的顶部附近。这一行定义了material Assets的文件GUID。要找到本地ID,请在文本编辑器中打开材质文件。物质对象的定义是这样的:
--- !u!21 &2100000
Material:
serializedVersion:
3 ... more data …
In the above example, the number preceded by an ampersand is the material's Local ID. If this material Object were located inside an Asset identified by the File GUID "abcdefg", then the material Object could be uniquely identified as the combination of the File GUID "abcdefg" and the Local ID "2100000".
之前在上面的例子中,数字前面一个&就是材质的Local ID。如果这个材质对象(material Object)是在一个由File GUID “abcdefg”标识的Asset资产文件中,那么这个material Object可以File GUID“abcdefg”和Local GUID“2100000”的组合唯一标识。
2.3. Why File GUIDs and Local IDs?
Why is Unity's File GUID and Local ID system necessary? The answer is robustness and to provide a flexible, platform-independent workflow.
为什么Unity的File GUID 和Local ID系统是必要的?答案是鲁棒性和提供灵活的、独立于平台的工作流。
The File GUID provides an abstraction of a file's specific location. As long as a specific File GUID can be associated with a specific file, that file's location on disk becomes irrelevant. The file can be freely moved without having to update all Objects referring to the file.
File GUID提供了文件具体位置的抽象。只要特定File GUID可以与特定文件关联,该文件在磁盘上的位置就变得不相关。该文件可以自由移动,而不必更新引用该文件的所有对象。
As any given Asset file may contain (or produce via import) multiple UnityEngine.Object resources, a Local ID is required to unambiguously distinguish each distinct Object.
因为任何给定的Asset 文件可能包含(或通过导入产生)多个UnityEngine.Object 资源,需要一个Local ID来明确区分每个不同的对象。
If the File GUID associated with an Asset file is lost, then references to all Objects in that Asset file will also be lost. This is why it is important that the .meta files must remain stored with the same file names and in the same folders as their associated Asset files. Note that Unity will regenerate deleted or misplaced .meta files.
如果与Asset 文件关联的 File GUID丢失,那么对该资产文件中所有对象的引用也将丢失。这就是.meta文件必须以相同的文件名存储在与其关联的Asset文件相同的文件夹中的原因。注意Unity会重新生成被删除或放错位置的.meta文件。
The Unity Editor has a map of specific file paths to known File GUIDs. A map entry is recorded whenever an Asset is loaded or imported. The map entry links the Asset's specific path to the Asset's File GUID. If the Unity Editor is open when a .meta file goes missing and the Asset's path does not change, the Editor can ensure that the Asset retains the same File GUID.
Unity编辑器有一个到从特定文件路径到已知File GUIDs的的映射。每当加载或导入资产时,都会记录一个map条目。map条目将Asset的特定路径链接到Asset的File GUID。如果Unity编辑器打开时,.meta文件丢失了,并且Asset的路径没有改变,编辑器可以确保资产保持相同的File GUID。【注:此话可理解为:File GUID是由特定路径的信息生成的,经简单测试,Asset的名称不会对File GUID产生影响】
If the .meta file is lost while the Unity Editor is closed, or the Asset's path changes without the .meta file moving along with the Asset, then all references to Objects within that Asset will be broken.
如果.meta文件在Unity编辑器关闭的时候丢失了,或者资产的路径在没有。meta文件随资产移动的情况下发生了变化,那么所有对该资产中对象的引用都将被破坏。
2.4. Composite Assets and importers
As mentioned in the Inside Assets and Objects section, non-native Asset types must be imported into Unity. This is done via an asset importer. While these importers are usually invoked automatically, they are also exposed to scripts via the AssetImporter API. For example, the TextureImporter API provides access to the settings used when importing individual texture Assets, such as PNG files.
正如在内部Assets和Objects部分中提到的,必须将非原生Asset类型导入到Unity中。这是通过asset导入器完成的。虽然这些导入器通常是自动调用的,但它们也会通过AssetImporter API暴露给脚本。例如,TextureImporter API提供了在导入单个纹理Assets(如PNG文件)时使用的设置的入口。
The result of the import process is one or more UnityEngine.Objects. These are visible in the Unity Editor as multiple sub-assets within the parent Asset, such as multiple sprites nested beneath a texture Asset that has been imported as a sprite atlas. Each of these Objects will share a File GUID as their source data is stored within the same Asset file. They will be distinguished within the imported texture Asset by a Local ID.
导入过程的结果是一个或多个UnityEngine.Objects。这些在Unity编辑器中是可见的,作为父资产中的多个子资产,例如多个精灵嵌套在一个已经作为精灵图集导入的纹理资产下。这些对象中的每一个都将共享一个文件GUID,因为它们的源数据存储在同一个Asset文件中。它们将在导入的纹理资产中通过Local ID进行区分。
The import process converts source Assets into formats suitable for the target platform selected in the Unity Editor. The import process can include a number of heavyweight operations, such as texture compression. As this is often a time-consuming process, imported Assets are cached in the Library folder, eliminating the need to re-import Assets again on the next Editor launch.
导入过程将源Assets 转换为适合于在Unity编辑器中选择的目标平台的格式。导入过程可以包括一些重量级(耗时)的操作,比如纹理压缩。由于这通常是一个耗时的过程,所以导入的Assets 会缓存在Library文件夹中,这样就不需要在下一次编辑器启动时再次导入Assets 。
Specifically, the results of the import process are stored in a folder named for the first two digits of the Asset's File GUID. This folder is stored inside the Library/metadata/ folder. The individual Objects from the Asset are serialized into a single binary file that has a name identical to the Asset's File GUID.
具体来说,导入过程的结果存储在以Asset的File GUID的前两位数字命名的文件夹中。该文件夹存储在Library/metadata/ folder中。资产中的单个对象被序列化为一个二进制文件,该文件的名称与Asset的File GUID相同。
This process applies to all Assets, not just non-native Assets. Native assets do not require lengthy conversion processes or re-serialization.
这个过程适用于所有Assets,而不仅仅是非原生的Assets。本机Assets不需要冗长的转换过程或重新序列化(re-serialization)。
2.5. Serialization and instances
While File GUIDs and Local IDs are robust, GUID comparisons are slow and a more performant system is needed at runtime. Unity internally maintains a cache that translates File GUIDs and Local IDs into simple, session-unique integers (note: Internally, this cache is called the PersistentManager.) These integers are called Instance IDs, and are assigned in a simple, monotonically-increasing order when new Objects are registered with the cache.
虽然File GUID和Local ID是健壮的,但是GUID的比较很慢,并且在运行时需要一个性能更好的系统。Unity在内部维护一个缓存,将File GUID和Local ID转换为简单的、会话(期间)唯一的整数(注意:在内部,这个缓存被称为PersistentManager)。这些整数被称为Instance IDs,当新对象注册到缓存中时,Instance IDs以简单的、单调递增的顺序指定。
The cache maintains mappings between a given Instance ID, File GUID and Local ID defining the location of the Object's source data, and the instance of the Object in memory (if any). This allows UnityEngine.Objects to robustly maintain references to each other. Resolving an Instance ID reference can quickly return the loaded Object represented by the Instance ID. If the target Object is not yet loaded, the File GUID and Local ID can be resolved to the Object's source data, allowing Unity to load the object just-in-time.
缓存维护给定Instance ID、File GUID和Local ID定义的对象源数据的位置(the location of the Object's source data),内存中的对象实例(the instance of the Object)(如果有的话)之间的映射。这允许UnityEngine.Objects健壮地维护对彼此间的引用。解析一个Instance ID引用可以快速返回由Instance ID表示的已加载对象。如果目标对象还没有加载,File GUID和Local ID可以解析为对象的源数据(the Object's source data),允许Unity在运行时(just-in-time)加载对象。
At startup, the Instance ID cache is initialized with data for all Objects immediately required by the project (i.e., referenced in built Scenes), as well as all Objects contained in the Resources folder. Additional entries are added to the cache when new assets are imported at runtime and when Objects are loaded from AssetBundles (note: An example of an Asset created at runtime would be a Texture2D Object created in script, like so: var myTexture = new Texture2D(1024, 768);). Instance ID entries are only removed from the cache when an AssetBundle providing access to a specific File GUID and Local ID is unloaded. When this occurs, the mapping between the Instance ID, its File GUID and Local ID are deleted to conserve memory. If the AssetBundle is re-loaded, a new Instance ID will be created for each Object loaded from the re-loaded AssetBundle.
在启动时,Instance ID cache被初始化为项目马上需要的所有对象(例如,build的场景中所引用的)的数据,以及Resources 文件夹中包含的所有对象。当在运行时导入新的assets 和从AssetBundles中加载对象时,额外的条目会添加到缓存中(注意:在运行时创建Asset的一个例子是在脚本中创建的Texture2D对象,如var myTexture = new Texture2D(1024,768);)。只有对特定File GUID和Local ID提供访问的AssetBuldle被卸载时,Instance ID条目才会从缓存中删除。当发生这种情况时,将删除实例ID、其文件GUID和本地ID之间的映射,以节省内存。如果重新加载了AssetBundle ,那么将为从重新加载的AssetBundle 中加载的每个对象创建一个新的实例ID。
For a deeper discussion of the implications of unloading AssetBundles, see the Managing Loaded Assets section in the AssetBundle Usage Patterns step.
有关卸载AssetBundles含义的更深入的讨论,请参阅Managing Loaded Assets section in the AssetBundle Usage Patterns step。
On specific platforms, certain events can force Objects out of memory. For example, graphical Assets can be unloaded from graphics memory on iOS when an app is suspended. If these Objects originated in an AssetBundle that has been unloaded, Unity will be unable to reload the source data for the Objects. Any extant references to these Objects will also be invalid. In the preceding example, the scene may appear to have invisible meshes or magenta textures.
在特定的平台上,某些事件可以强制对象从内存中移出。例如,当应用程序被挂起时,graphical Assets可以从iOS的图形内存中卸载。如果这些对象(【注:graphical Assets】)来自于一个已卸载的AssetBundle, Unity将无法为这些对象重新加载源数据。任何对这些对象的现存引用都是无效的。在前面的例子中,场景可能看起来有不可见的网格或洋红色纹理。
Implementation note: At runtime, the above control flow is not literally accurate. Comparing File GUIDs and Local IDs at runtime would not be sufficiently performant during heavy loading operations. When building a Unity project, the File GUIDs and Local IDs are deterministically mapped into a simpler format. However, the concept remains identical, and thinking in terms of File GUIDs and Local IDs remains a useful analogy during runtime. This is also the reason why Asset File GUIDs cannot be queried at runtime.
实现注意:在运行时,上面的控制流并不准确。在运行时比较File GUID和Local ID在大量加载操作期间不能充分发挥性能。当构建一个Unity项目时,File GUID和Local ID被确定地映射为一种更简单的格式。但是,概念仍然是相同的,运行时按照按照File GUID和Local ID来考虑仍然是的一个有用的类比。这也是为什么不能在运行时查询Asset File GUID的原因。
2.6. MonoScripts
It is important to understand that a MonoBehaviour has a reference to a MonoScript, and MonoScripts simply contain the information needed to locate a specific script class. Neither type of Object contains the executable code of script class.
了解MonoBehaviour含有对MonoScript的引用是很重要的,而MonoScripts仅仅包含了定位一个特定的脚本类所需要的信息。这两种类型的对象都不包含script类的可执行代码。
A MonoScript contains three strings: assembly name, class name, and namespace.
一个MonoScript 包含三个字符:程序集名称,类名和命名空间。
While building a project, Unity compiles all the loose script files in the Assets folder into Mono assemblies. C# scripts outside of the Plugins subfolder are placed into Assembly-CSharp.dll. Scripts within the Plugins subfolder are placed into Assembly-CSharp-firstpass.dll, and so on. In addition, Unity 2017.3 also introduces the ability to define custom managed assemblies.
在构建一个项目时,Unity会将Assets文件夹中的所有松散脚本文件编译成Mono程序集(Mono assemblies)。Plugins子文件夹外的C#脚本被放在Assembly-CSharp.dll中。Plugins子文件夹中的脚本被放置到Assembly-CSharp-firstpass.dll中,等等。此外,Unity 2017.3还引入了定义自定义托管程序集的功能。
These assemblies, as well as pre-built assembly DLL files, are included in the final build of a Unity application. They are also the assemblies to which a MonoScript refers. Unlike other resources, all assemblies included in a Unity application are loaded on application start-up.
这些程序集,以及预构建的(pre-buildt)程序集DLL文件,都包含在Unity应用程序的最终构建中。它们也是MonoScript引用的程序集。与其他资源不同,包含在Unity应用程序中的所有程序集都是在应用程序启动时加载的。
This MonoScript Object is the reason why an AssetBundle (or a Scene or a prefab) does not actually contain executable code in any of the MonoBehaviour Components in the AssetBundle, Scene or prefab. This allows different MonoBehaviours to refer to specific shared classes, even if the MonoBehaviours are in different AssetBundles.
此MonoScript对象是为什么AssetBundle(或场景或预制件)不实际包含AssetBundle,Scene或预制件中的任何MonoBehaviour组件中的可执行代码的原因。这允许不同的MonoBehaviours引用特定的共享类,即使MonoBehaviours位于不同的AssetBundle中。
【注:此话翻译较为拗口,且存疑】
2.7. Resource lifecycle
To reduce loading times and manage an application's memory footprint, it's important to understand the resource lifecycle of UnityEngine.Objects. Objects are loaded into/unloaded from memory at specific and defined times.
为了减少加载时间和管理应用程序的内存占用,理解UnityEngine.Objects的resource 的生命周期是很重要的。Objects 在特定的和明确的时间被加载到内存中或从内存中卸载。
An Object is loaded automatically when:
-
The Instance ID mapped to that Object is dereferenced
-
The Object is currently not loaded into memory
-
The Object's source data can be located.
一个Object被自动加载当:
- 当映射到该对象的Instance ID被解引用(注:解引用:获取引用所指向的对象)时。
- Object 当前没有被加载到内存中
- Object 的源数据可以被定位。
Objects can also be explicitly loaded in scripts, either by creating them or by calling a resource-loading API (e.g., AssetBundle.LoadAsset). When an Object is loaded, Unity tries to resolve any references by translating each reference's File GUID and Local ID into an Instance ID. An Object will be loaded on-demand the first time its Instance ID is dereferenced if two criteria are true:
-
The Instance ID references an Object that is not currently loaded
-
The Instance ID has a valid File GUID and Local ID registered in the cache
Object也可以在在脚本中显式加载,或通过调用资源加载API(resource-loading API)创建它们(例如,AssetBundle.LoadAsset)。当一个对象被加载时,Unity将尝试通过将每个引用的File GUID和Local ID转换为一个Instance ID解析任何引用,如果以下两个条件为真,那么对象将在它的Instance ID第一次解引用时按需加载:
- The Instance ID引用的对象当前没有加载
- The Instance ID有一个在缓存中注册过的有效的File GUID和Local ID
This generally occurs very shortly after the reference itself is loaded and resolved.
这通常发生在引用本身被加载和解析之后不久。
If a File GUID and Local ID do not have an Instance ID, or if an Instance ID with an unloaded Object references an invalid File GUID and Local ID, then the reference is preserved but the actual Object will not be loaded. This appears as a "(Missing)" reference in the Unity Editor. In a running application, or in the Scene View, "(Missing)" Objects will be visible in different ways, depending on their types. For example, meshes will appear to be invisible, while textures may appear to be magenta.
如果File GUID和Local ID没有Instance ID,或者Instance ID对应 的已卸载对象引用了无效的File GUID和Local ID,那么该引用将被保留,但不会加载实际的对象。这在Unity编辑器中作为“(Missing)”的引用出现。在运行的应用程序中,或在场景视图中,“(Missing)”对象将以不同的方式可见,这取决于它们的类型。例如,网格看起来是不可见的,而纹理可能是洋红色的。
Objects are unloaded in three specific scenarios:
-
Objects are automatically unloaded when unused Asset cleanup occurs. This process is triggered automatically when scenes are changed destructively (i.e. when SceneManager.LoadScene is invoked non-additively), or when a script invokes the Resources.UnloadUnusedAssets API. This process only unloads unreferenced Objects; an Object will only be unloaded if no Mono variable holds a reference to the Object, and there are no other live Objects holding references to the Object. Furthermore, note that anything marked with HideFlags.DontUnloadUnusedAsset and HideFlags.HideAndDontSave will not be unloaded.
- 当未使用的Asset清理发生时,对象将自动卸载。当场景破坏性的改变时(i.e.when SceneManager.LoadScene is invoked non-additively),这个过程会自动触发 ,或者当脚本调用Resources.UnloadUnusedAssets API时,这个过程只卸载未引用的对象,只有当没有Mono变量持有对该对象的引用,并且没有其他活动对象持有对该对象的引用时,该对象才会被卸载。此外,请注意任何标有HideFlags.DontUnloadUnusedAsset和HideFlags.HideAndDontSave的(对象)将不会被卸载。
-
Objects sourced from the Resources folder can be explicitly unloaded by invoking the Resources.UnloadAsset API. The Instance ID for these Objects remains valid and will still contain a valid File GUID and LocalID entry. If any Mono variable or other Object holds a reference to an Object that is unloaded with Resources.UnloadAsset, then that Object will be reloaded as soon as any of the live references are dereferenced.
- 可以通过调用Resources.UnloadAsset API显式地卸载来自Resources文件夹的对象。这些对象的实例ID仍然有效,并且仍然包含一个有效的File GUID和Local ID条目。如果任何Mono变量或其他对象持有对一个对象的引用,该对象已被Resources.UnloadAsset卸载。那么当任何活动引用被解引用时,该对象将被重新加载。
-
Objects sourced from AssetBundles are automatically and immediately unloaded when invoking the AssetBundle.Unload(true) API. This invalidates the File GUID and Local ID of the Object's Instance ID, and any live references to the unloaded Objects will become "(Missing)" references. From C# scripts, attempting to access methods or properties on an unloaded object will produce a NullReferenceException.
- 当调用AssetBundle.Unload(true) API时,来自AssetBundles 的对象会自动立即卸载。这将使对象Instance ID对应的File GUID和Local ID失效,并且任何对已卸载对象的活动引用都将成为“(Missing)”引用。在C#脚本中,试图访问已卸载对象的方法或属性将产生一个NullReferenceException异常。
If AssetBundle.Unload(false) is called, live Objects sourced from the unloaded AssetBundle will not be destroyed, but Unity will invalidate the File GUID and Local ID references of their Instance IDs. It will be impossible for Unity to reload these Objects if they are later unloaded from memory and live references to the unloaded Objects remain.
如果AssetBundle. unload (false)被调用,来自已卸载的AssetBundle的活对象将不会被销毁,但是Unity会这些对象的Instance ID对应的File GUID和Local ID失效。如果这些对象后来被从内存中卸载,并且仍然存在对已卸载对象的活动引用,那么Unity将不可能重新加载这些对象。
(Note: The most common case where Objects are removed from memory at runtime without being unloaded occurs when Unity loses control of its graphics context. This may occur when a mobile app is suspended and the app is forced into the background. In this case, the mobile OS usually evicts all graphical resources from GPU memory. When the app returns to the foreground, Unity must reload all needed Textures, Shaders and Meshes to the GPU before scene rendering can resume.)
(注意:最常见的情况是对象在运行时被从内存中删除而没有被卸载,发生在Unity失去了对其图形上下文的控制时。当一个移动应用程序被挂起并被迫进入后台时,可能会发生这种情况。在这种情况下,移动操作系统通常会从GPU内存中移除所有图形资源。当应用程序返回到前台时,Unity必须重新加载所有需要的Textures, Shaders and Meshes到GPU,然后场景渲染才能恢复。)
2.8. Loading large hierarchies
When serializing hierarchies of Unity GameObjects, such as during prefabs serialization, it is important to remember that the entire hierarchy will be fully serialized. That is, every GameObject and Component in the hierarchy will be individually represented in the serialized data. This has interesting impacts on the time required to load and instantiate hierarchies of GameObjects.
当序列化Unity GameObjects的层次结构时,比如在prefabs序列化期间,记住整个层次结构将被完全序列化是很重要的。也就是说,层次结构中的每个GameObject和组件都将在序列化数据中单独表示。这对加载和实例化游戏对象的层次结构所需的时间有有趣的影响。
When creating any GameObject hierarchy, CPU time is spent in several different ways:
当创建任何游戏对象层次,CPU时间花费在几个不同的方面:
-
Reading the source data (from storage, from an AssetBundle, from another GameObject, etc.)
- 读取源数据(从存储,从一个AssetBundle,从另一个游戏对象,等等)
-
Setting up the parent-child relationships between the new Transforms
- 在新Transforms之间建立父子关系
-
Instantiating the new GameObjects and Components
- 实例化新的GameObejct和组件
-
Awakening the new GameObjects and Components on the main thread
- 在主线程唤醒新的GameObject和组件
The latter three time costs are generally invariant regardless of whether the hierarchy is being cloned from an existing hierarchy or is being loaded from storage. However, the time to read the source data increases linearly with the number of Components and GameObjects serialized into the hierarchy, and is also multiplied by the speed of the data source.
后三种时间开销通常是不变的,不管层次结构是从现有层次结构克隆出来的还是从存储中加载出来的。然而,读取源数据的时间会随着序列化到层次结构中的组件和游戏对象的数量线性增加,而且还会乘以数据源的速度
On all current platforms, it is considerably faster to read data from elsewhere in memory rather than loading it from a storage device. Further, the performance characteristics of the available storage media vary widely between different platforms. Therefore, when loading prefabs on platforms with slow storage, the time spent reading the prefab's serialized data from storage can rapidly exceed the time spent instantiating the prefab. That is, the cost of the loading operation is bound to storage I/O time.
在所有当前的平台上,从内存中的其他地方读取数据要比从存储设备加载数据快得多。此外,可用存储媒介的性能特征在不同的平台之间差别很大。因此,当在存储速度较慢的平台上加载预制体时,从存储中读取预制体的序列化数据所花费的时间会迅速超过实例化预制体所花费的时间。也就是说,加载操作的成本受限于存储I/O时间。
As mentioned before, when serializing a monolithic prefab, every GameObject and component's data is serialized separately, which may duplicate data. For example, a UI screen with 30 identical elements will have the identical element serialized 30 times, producing a large blob of binary data. At load time, the data for all of the GameObjects and Components on each one of those 30 duplicate elements must be read from disk before being transferred to the newly-instantiated Object. This file reading time is a significant contributor to the overall cost of instantiating large prefabs. Large hierarchies should be instantiated in modular chunks, and then be stitched together at runtime.
如前所述,当序列化一个单庞大的预制体时,每个GameObject和Component的数据都是单独序列化的,这可能会复制数据。例如,具有30个相同元素的UI屏幕将会将相同元素序列化30次,从而产生大量二进制数据。在加载的时候,所有的游戏对象和组件的数据在被转移到新实例化的对象之前必须从磁盘上读取那30个重复的元素。此文件读取时间是实例化大型预置的总体成本的重要因素。大型层次结构应该在模块化的块中实例化,然后在运行时合并在一起。
Unity 5.4 note: Unity 5.4 altered the representation of transforms in memory. Each root transform's entire child hierarchy is stored in compact, contiguous regions of memory. When instantiating new GameObjects that will be instantly reparented into another hierarchy, consider using the new GameObject.Instantiate overloaded variants which accept a parent argument. Using this overload avoids the allocation of a root transform hierarchy for the new GameObject. In tests, this speeds up the time required for an instantiate operation by about 5-10%.
注意:Unity 5.4改变了transforms 在内存中的表示。每个根transform的整个子层次结构存储在紧凑的、连续的内存区域中。当实例化新的游戏对象时,它将立即被重定父级到另一个层次中,考虑使用新的GameObject.Instantiate接受父参数的重载变体。使用这个重载避免为新的游戏对象分配一个根transform 层次。在测试中,这将使实例化操作所需的时间增加约5-10%。