Transferred from: http://www.jianshu.com/p/b37ee8cea04c
1. Resource types
Gameobject, Transform, Mesh, Texture, Material, Shader, script and various other assets.
2. How resources are created
- Static Reference, add a public gameobject variable in the script, drag a prefab to the variable in the Inspector panel, and then instantiate where the reference is needed;
- Resource.load, the resource needs to be placed in the assets/resources directory;
- assetbundle.load, after Load instantiate. 3. Resource Destruction Mode
- Gameobject.destroy (gameobject), destroying the object,
- Assetbundle.unload (false), releasing the Assetbundle file memory image, The assets object created by load is not destroyed;
- Assetbundle.unload (True), releasing the Assetbundle file memory image while destroying all the assets memory images that have been load;
- Resources.unloadasset (object), releasing the loaded asset object,
- resources.unloadunusedassets, releasing all asset objects that are not referenced. 4. The life cycle experiment has created a simple scenario in which an empty gameobject is created, a script is hung on it, and a awake function is created to create resources in the Coroutine function. The prefab created in the
experiment was a tank car, adding about 3M of scene memory in the scene and creating a Assetbundle resource for assetbundle use. 1. Resources.load mode to load a prefab, and then instantiate Gameobject code as follows:
IEnumerator LoadResources() { // 清除干净以免影响测试结果 Resources.UnloadUnusedAssets(); // 等待5秒以看到效果 yield return new WaitForSeconds(5.0f); // 通过Resources.Load加载一个资源 GameObject tank = Resources.Load("Role/Tank") as GameObject; yield return new WaitForSeconds(0.5f); // Instantiate一个资源出来 GameObject tankInst = GameObject.Instantiate(tank, Vector3.zero, Quaternion.identity) as GameObject; yield return new WaitForSeconds(0.5f); // Destroy一个资源 GameObject.Destroy(tankInst); yield return new WaitForSeconds(0.5f); //释放无用资源 tank = null; Resources.UnloadUnusedAssets(); yield return new WaitForSeconds(0.5f); }
The results of the implementation are as follows:
Here are the statistical results:
Data Description |
Memory |
Texture |
Mesh |
Material |
gameobjects |
Objects in Scene | Total
Objects |
Initial |
72.8M |
1271/8.0m |
35/223.0k |
25/10.2k |
7 |
211 |
2187 |
Resources.load |
72.8M |
1271/8.0m |
36/0.8m |
25/10.2k |
7 |
211 |
2280 |
Instantiate |
75.3M |
1272/9.3m |
36/0.8m |
26/10.7k |
52 |
303 |
2375 |
Destroy |
74.7M |
1272/9.3m |
36/0.8m |
26/10.7k |
7 |
211 |
2283 |
Resources.unloadunusedassets |
72.3M |
1271/8.0m |
35/223.0k |
25/10.2k |
7 |
211 |
2187 |
From here we draw the following conclusions:
- Resouces.load A prefab is a relatively lightweight operation relative to instantiate a resource, resources.load loading a prefab consumes almost no memory, while instantiate consumes 2.5M of resource space. Resources.load increases the number of mesh and total objects, while instantiate increases the number of gameobjects,objects in scene and Total Objects;
- Destroy after a gameobject, memory is reduced, but less, in this case, the material and texture in this example are reduced by 0.6m;instantiate and destroy, and are not restored to continue the instantiate later.
If Resources.unloadunusedassets is not called, the result is as follows:
The statistical results are as follows:
Data Description |
Memory |
Texture |
Mesh |
Material |
gameobjects |
Objects in Scene | Total
Objects |
Initial |
58.9M |
1258/7.5m |
34/219.2k |
22/9.0k |
7 |
117 |
2078 |
Resources.load |
60.0M |
1258/7.5m |
35/0.8m |
22/9.0k |
7 |
117 |
2171 |
Instantiate |
62.5M |
1259/8.9m |
36/0.8m |
23/9.5k |
52 |
209 |
2256 |
Destroy |
61.8M |
1259/8.9m |
35/0.8m |
23/9.5k |
7 |
117 |
2174 |
The following conclusions are drawn:
If you do not perform resources.unloadunusedassets manually, redundant mesh,material and objects are not actively freed.
2. Load a prefab in a assetbundle.load manner, and then instantiate a Gameobject
The code is as follows:
IEnumerator LoadAssets(string path) { // 清除干净以免影响测试结果 Resources.UnloadUnusedAssets(); // 等待5秒以看到效果 yield return new WaitForSeconds(5.0f); // 创建一个WWW类 WWW bundle = new WWW(path); yield return bundle; yield return new WaitForSeconds(0.5f); // AssetBundle.Load一个资源 Object obj = bundle.assetBundle.Load("tank"); yield return new WaitForSeconds(0.5f); // Instantiate一个资源出来 GameObject tankInst = Instantiate(obj) as GameObject; yield return new WaitForSeconds(0.5f); // Destroy一个资源 GameObject.Destroy(tankInst); yield return new WaitForSeconds(0.5f); // Unload Resources bundle.assetBundle.Unload(false); yield return new WaitForSeconds(0.5f); // 释放无用资源 //obj = null; //Resources.UnloadUnusedAssets(); yield return new WaitForSeconds(0.5f); }
The results of the implementation are as follows:
The statistical results are as follows:
Data Description |
Memory |
Texture |
Mesh |
Material |
gameobjects |
Objects in Scene | Total
Objects |
Initial |
59.9M |
1267/7.8m |
35/223.0k |
25/10.2k |
7 |
127 |
2099 |
New WWW |
62.0M |
1267/7.8m |
35/223.0k |
25/10.2k |
7 |
127 |
2099 |
Assetbundle.load |
64.5M |
1268/9.2m |
36/0.8m |
26/10.5k |
7 |
127 |
2196 |
Instantiate |
65.6M |
1268/9.2m |
36/0.8m |
26/10.7k |
52 |
219 |
2288 |
Destroy |
63.9M |
1268/9.2m |
36/0.8m |
26/10.7k |
7 |
127 |
2196 |
Assetbundle.unload |
63.7M |
1268/9.2m |
36/0.8m |
26/10.7k |
7 |
127 |
2196 |
Resources.unloadunusedassets |
61.8M |
1267/7.8m |
35/223.0k |
25/10.2k |
7 |
127 |
2099 |
The following conclusions are drawn:
The mesh,texture and material are loaded automatically when a resource is loaded via the WWW load assetbundle, and loading with the Resouces.load mode loads only the mesh information. As a result, the memory consumption of instantiate a resource is smaller after loading by assetbundle mode, in this case Assetbundle.load adds 2.5M of memory, and instantiate adds 1.1M of memory. The memory increment of instantiate is much smaller compared to resources.load.
3. Instantiate a resource by means of a static binding
The code is as follows:
IEnumerator InstResources() { Resources.UnloadUnusedAssets(); yield return new WaitForSeconds(5.0f); GameObject inst = GameObject.Instantiate(tank, Vector3.zero, Quaternion.identity) as GameObject; yield return new WaitForSeconds(1f); GameObject.Destroy(inst); yield return new WaitForSeconds(1f); //释放无用资源 tank = null; Resources.UnloadUnusedAssets(); yield return new WaitForSeconds(1f); }
The results of the implementation are as follows:
The statistical results are as follows:
Data Description |
Memory |
Texture |
Mesh |
Material |
gameobjects |
Objects in Scene | Total
Objects |
Initial |
62.0M |
1268/7.9m |
36/0.8m |
25/10.2k |
7 |
134 |
2202 |
Instantiate |
64.4M |
1269/9.2m |
36/0.8m |
26/10.7k |
8 |
137 |
2207 |
Destroy |
64.0M |
1269/9.2m |
36/0.8m |
26/10.7k |
7 |
134 |
2204 |
Unloadunused Resources |
62.3M |
1268/7.9m |
35/226.3k |
25/10.2k |
7 |
134 |
2107 |
The following conclusions are drawn:
By statically binding the load order of various resources is the same as Resources.load, when a gameobject is created, its component statically bound Gameobject only loads the mesh information, only if the Gameobject Texture and material information will not be loaded until instantiate is released.
Theory Chapter
The process of loading resources can be divided into two phases, the first phase is to load various resources using Resources.load or assetbundle.load, and the second phase is to clone a new gameobject using Gameobject.instantiate.
The types of load resources include Gameobject, Transform, Mesh, Texture, Material, shader, and script. But there is a difference between resources.load and assetbundle.load.
When using Resources.load, the corresponding asset object was not created until the first instantiate, and it was not actually read until the first instantiate to create these assets. Its purpose is to implement a way of using OnDemand to create these resources when the resource is actually used.
When using the Assetbundle.load method, the resource files are read directly to create these assets, so the first instantiate will be relatively small.
These differences can help us explain why there is a noticeable lag when launching the first bullet.
Then we'll look at the instantiate process. The process of instantiate is a process of combining clone (copy) and reference to assets, and the process of cloning requires the memory to store its own data, whereas the process of referencing only needs to direct a simple pointer to a resource that has already been load. For example, transform is out of clone, texture and Terraindata are copied by reference, and mesh,material,physicalmaterial and script are both clone and reference. In script, for example, the script is divided into code snippets and data segments, all the code that needs to use the script is the same, and everyone's data is different, so you need to use clone for the data segment, and the code snippet needs to be gameobject in the way it is referenced.
Therefore the load operation actually load some data source, used to create a new object is clone or referenced.
Then is the process of destroying resources. When destory a gameobject or other instance, it releases only those clone assets from the instance, and does not release those referenced assets, because destroy does not know if anyone else is referencing the assets. When no objects in the scene refer to these assets, they become unusedassets, which can be released by Resources.unloadunusedassets. Assetbundle.unload (false) does not work because it frees only the memory image of the file, does not release the resource, and Assetbunde.unload (true) is not possible because it is a release of violence, and there may be other objects referencing the assets, Brute force release can cause program errors.
It is also important to note that all memory objects are automatically destroyed when the system loads a new scene, including resources.load loaded assets, statically bound assets, Assetbundle.load loaded resources and instantiate instantiated objects. However, Assetbundle.load's own file memory image (used to create various asset) is not automatically destroyed, which must be actively destroyed using Assetbundle.unload (false). The recommended practice is to call Assetbunble.unload (false) to destroy the file memory image immediately after the resource is loaded.
Can help understand the relationship between asset and Gameobject in memory.
Concluding article
- In order to avoid the phenomenon of the first instantiate, it is recommended to use Assetbundle.load instead of resources.load to load the resources in a way;
- Immediately after the resource is loaded, call Assetbunble.unload (false) to release the file memory image;
- Unity itself does not provide a good memory application and release management mechanism, destroy a gameobject will immediately release memory instead of internal cache, so the application of frequently used objects such as NPC,FX, such as the object pool management is necessary to reduce the number of memory applications;
- When to Resources.unloadunusedassets is an issue that needs to be discussed.
REF:
http://game.ceeger.com/forum/read.php?tid=4394
http://game.ceeger.com/forum/read.php?tid=4466
Unity Memory Request and release