Unity3d Memory Management and optimization

Source: Internet
Author: User
Tags class definition shallow copy

There are two dynamic loading mechanisms in unity: One is resources.load, the other is through Assetbundle. Resources.load is from a default into the package Assetbundle loading resources, and general Assetbundle files need you to create, run-time dynamic loading, you can specify the path and source.

Elaborate on the concept of detail:

Assetbundle Run-time loading:

CreateFromFile from the file (note that this method can only be used for standalone programs) This is the fastest way to load,

Can also come from memory, with Createfrommemory (byte[]), this byte[] can be from file read buffer, www download or other possible way. In fact, www assetbundle is the internal data read after the automatic creation of a assetbundle just, create after, is equal to the hard disk or the network of a file read into an area of memory, this time is only a assetbundle memory image data block, There is no concept of assets.

Assets Loading:

With Assetbundle.load (same as Resources.load) this will read and create a asset object from the Assetbundle memory image, and the asset object will also be allocated with the corresponding memory for storage (deserialization). Asynchronous read with Assetbundle.loadasync can also read multiple Assetbundle.loadall

Release of Assetbundle:

Assetbundle.unload (flase) is a memory image that releases assetbundle files, does not contain asset memory objects created by load, assetbundle.unload (TRUE) is to release that assetbundle file memory image and destroy all asset memory objects created with load. A prefab load from the Assetbundle, which may include: Gameobject, transform, mesh, texture, material, shader, script, and various other assets.

Instaniate a prefab is a combination of clone (copy) and reference to assets, Gameobject, transform is clone is newly generated. Other Mesh/texture/material/shader, some of which are purely reference relationships, include: texture and terraindata, as well as references and replication, including: mesh/material/ Physicmaterial. The referenced asset object is not copied, just a simple pointer to the asset object that has already been load.

        specifically to mention is a special thing: Script Asset. It seems strange that every script in unity is a closed class definition and does not write the calling code, and the definition script of the light class does not work. In fact, the unity engine is the calling code, clone a script asset equals the new class instance, the instance will finish the work. Hang him in the call chain of the unity main thread, and the OnUpdate OnStart in the class instance will be executed. More than one object hangs the same script, in fact, it is to hang the multiple instances of the script class on more than one object, so it is understandable. In the process of new class, the data area is copied, and the code area is shared, which is a special copy + reference relationship. You can instaniate a similar prefab, or this set of Mesh/texture/material/shader ..., this time there will be a new gameobject, etc., but will not create a new reference object such as texture.

        So the assets that you load is actually a data source that is used to generate new objects or to be referenced, and the resulting process might be a copy (clone) or a reference (pointer). When you destroy an instance, just release those clone objects and do not release the data source object that references the object and clone, destroy does not know if there are any other objects that reference them. Wait until there is no game scene object after using these assets, these assets become the free data block without reference, it is unusedassets, At this point can be released through Resources.unloadunusedassets, destroy cannot complete this task, Assetbundle.unload (false) also not, Assetbundle.unload (true) Yes, but not safe, unless you know that no object is using these assets.
with a diagram to deepen understanding:


is called asset, but the copy and reference is not the same, this is masked by unity's dark technical details, need to understand.

      about memory management, in accordance with traditional programming thinking, the best way is to maintain all the objects themselves, with a queue to save all the object, not when the destory, the unload's own processing. But this is a bit unnecessary and cumbersome under the C #. NET Framework.
on the safe side you can manage this:

When creating, first build a assetbundle, whether from www or file or memory with Assetbundle.load load required asset immediately after loading Assetbundle.unload (false), Releases the memory image of the Assetbundle file itself, but does not destroy the loaded asset object. (so you don't have to save the Assetbundle reference and you can immediately release a portion of the memory)
When released, if there are instantiate objects, destroy with Destroy, call Resources.unloadunusedassets at the appropriate place, release the asset that have not been referenced, and if necessary immediately release the memory plus Gc.collect ( ), otherwise the memory may not be released immediately, which can sometimes lead to excessive memory consumption and throw an exception. This ensures that the memory is always released in a timely manner, taking the least amount. There is also no need to reference each loaded object. This is not the only way, of course, as long as you follow the principle of loading and releasing, anything can be done.

When the system loads a new scene, all the memory objects are automatically destroyed, including the objects you loaded with Assetbundle.load and the Instaniate clones. But it does not include the memory image of the Assetbundle file itself, which must be freed with unload, and in. NET terms, this data cache is unmanaged.

Summarize the various loading and initialization uses:

Assetbundle.createfrom ..... : Create a Assetbundle memory image, and note that the same Assetbundle file cannot be used again until it is unload WWW.AssetBundle: Ditto, of course, first new one, then yield return. Before you can use Assetbundle.load (name): reads a asset of the specified name from the Assetbundle and generates a asset memory object, and if multiple Load objects of the same name are returned, only the asset objects that have been generated will return, except for the first time. That is, multiple load a asset does not generate more than one copy (singleton).

Resources.load (Path&name): Ditto, just load from the default location.

Instantiate (object): Clone a complete structure of an object, including all its component and sub-objects (see official documentation), shallow copy, and does not copy all reference types. There is a special usage, although rarely used, in fact, can be used instantiate to complete the copy of a reference type of asset, such as texture, to copy the texture must be type set to read/write able.


Summarize the various releases

Destroy: Used primarily for destroying cloned objects or for static objects within a scene, and does not automatically release all references to the object. Although it can also be used for asset, the concept is not as careful if the asset object that is used to destroy the load from the file destroys the corresponding resource file. However, if the destroyed asset is copy or dynamically generated with a script, only the memory object will be destroyed.

Assetbundle.unload (FALSE): Release Assetbundle file memory image

Assetbundle.unload (TRUE): Releases Assetbundle file memory image while destroying all assets memory objects that have already been load

Reources.unloadasset (object): explicitly releasing loaded asset objects, only unloading asset objects loaded by the disk file

Resources.unloadunusedassets: Used to release all asset objects that are not referenced

Gc. Collect (): Force garbage collector to release memory immediately Unity's GC function is not good, and when you're not sure, force a call.

Give two examples to help understand
Example 1:
A common mistake: you load a prefab from a assetbundle and clone it: O

Bj=instaniate (Assetbundle1.load (' Myprefab ");

This prefab, for example, is an NPC, and then you do not need him when you use: Destroy (obj); you think it's free, but you just release the Clone object, all references, non-reference assets objects loaded by load are all quietly lying in memory. This situation should be used after destroy: Assetbundle1.unload (True), completely released cleanly. If this AssetBundle1 is to be read repeatedly, inconvenient unload, that can be used after destroy: Resources.unloadunusedassets () to all and this NPC related asset are destroyed.
Of course, if the NPC is to be frequently created and destroyed, then those assets should be kept in memory to speed up the gaming experience.
This can explain another topic that was previously mentioned: Why Instaniate a prefab in the first time, because the corresponding asset object has not been created before your first instaniate, To load the system built-in assetbundle and create assets, the first time after you destroy, but prefab assets objects are still in memory, so soon.



By the way, the difference between several loading methods:
There are actually 3 ways to load:
One is static reference, build a public variable, in the Inspector Prefab pull up, use when instantiate
The second is resource.load,load after instantiate
Three is assetbundle.load,load after instantiate
There are three ways to have the details difference, the first two methods, the reference object texture is loaded at instantiate, and Assetbundle.load will perfab all assets loaded, instantiate just to generate clone. So in the first two ways, unless you load the relevant reference object in advance, the first instantiate will contain the operation that loads the reference assets, causing the lag to load for the first time.


Example 2:
Reads a 1.unity3d file from disk into memory and builds a AssetBundle1 object
Assetbundle AssetBundle1 = Assetbundle.createfromfile ("1.unity3d");
Read and create a texture Asset from the AssetBundle1 and point the obj1 main map to it
Obj1.renderer.material.mainTexture = Assetbundle1.load ("Wall") as Texture;
The OBJ2 's main map also points to the same texture Asset
Obj2.renderer.material.mainTexture =obj1.renderer.material.maintexture;
Texture is a reference object and will never have automatic replication (unless you really need to implement copy with your code), just create and add references
If you continue:
Assetbundle1.unload (True) that obj1 and obj2 all turned black, because the texture asset to the point was gone.
If:
Assetbundle1.unload (false) that obj1 and obj2 do not change, just the memory image of AssetBundle1 is released
Go on:
Destroy (OBJ1),//obj1 is released, but does not release the texture of the load just now
If this is the case:
Resources.unloadunusedassets ();
There will be no memory release because texture asset is still being used by OBJ2.
If
Destroy (OBJ2)
Obj2 is released, but will not release the texture of the load just now.
Go on
Resources.unloadunusedassets ();
This time the load texture asset was released because there was no reference to the
Last Cg.collect ();
Force immediate free memory
This can be derived from the forum of another has been raised a few questions, how to load a large number of pictures in turn show do not explode
Do not consider assetbundle, directly with the WWW read the picture file is equal to directly created a texture Asset
Suppose the file is saved in a list.
Tllist<string> fileList;
int n=0;
IEnumerator OnClick ()
{
www image = new www (filelist[n++]);
yield return image;
Obj.maintexture = image.texture;

n = (n>=filelist.length-1)? 0:n;
Resources.unloadunusedassets ();
}
This ensures that there is always only one giant texture Asset resource in memory and no code to track the last loaded texture Asset, but slower
Or:
IEnumerator OnClick ()
{
www image = new www (filelist[n++]);
yield return image;
Texture tex = obj.maintexture;
Obj.maintexture = image.texture;

n = (n>=filelist.length-1)? 0:n;
Resources.unloadasset (Tex);
}
It's faster to unload

Hog's comments Quote: Feel this is the place where unity memory management is dark and chaotic, especially when it comes to texture
I've been testing these lately, too.

Assetbundle loaded with asset can be unloaded with resources.unloadunusedassets, but must be assetbundle.unload before it is recognized as useless asset.

The Safer Way is
When created:
First build a assetbundle, whether from www or file or memory
Load the required asset with Assetbundle.load
Assetbundle.unload (false) immediately after use, close assetbundle but do not destroy created objects and references
When destroyed:
Destroy the object of the instantiate
Call Resources.unloadunusedassets at the appropriate place to release the asset that have not been referenced.
If needed immediately release plus gc.collect ()
This will ensure that memory is always released in a timely manner.
As long as you unload the Assetbundle, those created objects and references will be automatically freed when Loadlevel.

[Script] full understanding of unity loading and memory management mechanism: further depth and detail

All in one post content too much, here another one to continue to explore

The differences between several dynamic load prefab modes of unity:
In fact there are 3 ways to load prefab:
One is static reference, build a public variable, in the Inspector Prefab pull up, use when instantiate
The second is resource.load,load after instantiate
Three is assetbundle.load,load after instantiate
There are three ways to have the details difference, the first two methods, the reference object texture is loaded at instantiate, and Assetbundle.load will perfab all assets loaded, instantiate just to generate clone. So in the first two ways, unless you load the related reference object in advance, the first instantiate will contain the operation that loads the reference class assets, causing the lag to load for the first time. Official Forum Some people say that resources.load and static references are pre-loaded for all resources, the results of repeated tests, static references and resources.load are also OnDemand, and will only be loaded when used.


Differences in how several assetbundle are created:
CreateFromFile: This way does not load the entire hard disk Assetbundle files into memory, but rather similar to the creation of a file operation handle and buffer, real-time load when needed, so this loading method is the most resource-saving, Basically assetbundle itself does not account for any memory, only the memory of the asset object is required. Unfortunately, it can only be used in Pc/mac standalone programs.
Createfrommemory and Www.assetBundle: In both ways assetbundle files are mirrored in memory, in theory the size of the file requires much memory, and then the load consumes additional memory to generate the asset object.

When is Unusedassets?
See an example:
Object obj = resources.load ("Myprefab");
Gameobject instance = Instantiate (obj) as gameobject;
.........
Destroy (instance);
The creation then destroys a prefab instance, when Myprefab has not been referenced by the actual object, but if:
Resources.unloadunusedassets ();
The memory is not released because Myprefab is also referenced by this variable, obj
This time
obj = null;
Resources.unloadunusedassets ();
So that you can really release the assets object
So: Unusedassets not only to be referenced by the actual object, but also not to be referenced by a variable in the life cycle, it can be understood as Unused (reference count is 0)
So: If you use a global variable to save your load's assets, and you don't explicitly set it to NULL, then you unloadunusedassets not be able to release those assets before the variable expires. If you assets are not loaded from disk, there is no other way to unload it except unloadunusedassets or loading a new scene.


A complex example, the code is ugly and actually it is impossible to do so, just to deepen understanding copy code IEnumerator OnClick () {    resources.unloadunusedassets () ;//clean to avoid affecting the test effect     yield return new Waitforseconds (3);     float wait = 0.5f;     //uses WWW to read a assetbundle, inside is a unity basic sphere and a material with a large map, is a prefab     www AA = New WWW (@ "File://SpherePrefab.unity3d");     yield return AA;     assetbundle asset = Aa.assetbundle;     yield return new Waitforseconds (wait)//wait 0.5s per step for easy analysis of results     texture TT = asset. Load ("balltexture") as  texture;//load map     yield return new waitforseconds (wait);     gameobject ba = asset. Load ("Sphereprefab") as  gameobject;//load prefab     yield return new Waitforseconds ( Wait);     gameobject obj1 = Instantiate (BA) as gameobject;//generation instance     yieldreturn new Waitforseconds (wait);     destroy (obj1);//Destroy Instance     yield return new Waitforseconds (wait);     asset. Unload (false);//unload Assetbundle     yield return new waitforseconds (wait);     resources.unloadunusedassets ();//unload Useless resources     yield return new Waitforseconds (wait);     ba = null;//The prefab reference is empty after unloading the useless load resources    resources.unloadunusedassets ();    yield return new waitforseconds (wait);    TT = null;//The texture reference to empty after uninstalling useless resources    resources.unloadunusedassets (); }


This is the memory profile graph of the test results.

Image: P12.jpg


It's a classic symmetrical shape, with how much to release.

This is the memory and other data changes at each stage

Image: P13.jpg


Description
1 Initial state
2 after loading the Assetbundle file, the memory of the file image, the amount of increase, total object and assets increased by 1 (Assetbundle is also an object)
3 load texture, memory continues to rise, because more texture asset,total objects and assets increased by 1
4 after loading the prefab, there is no noticeable change in memory because the texture of memory is already loaded, materials is increased because of the prefab material, total objects and assets increased by 6, because Perfab contains many components
5 after instantiating prefab, the memory texture memory, gameobjecttotal, Objects in scene rise, all because a visual object is instantiated
6 After destroying the instance, restore the changes in the previous step, well understood
7 After uninstalling the Assetbundle file, the memory occupied by the Assetbundle file image is freed, and the corresponding assets and total Objects count are also reduced by 1
8 direct resources.unloadunusedassets, without any change, since all assets references are not emptied
9 after the prefab reference variable is set to NULL, the entire prefab has no references except texture, so it is unloadunusedassets destroyed, assets and total Objects count minus 6
10 The reference variable of texture is then set to NULL, then also destroyed by Unloadunusedassets, memory is freed, assets and total Objects count minus 1, basic restore to initial state

It can also be seen from:
Texture after loading is to memory, display the time to enter the memory of texture memory.
All things are based on object.
Load's asset,instantiate is Gameobject and object in Scene
The asset of load should be unload,new or instantiate object can be destroy

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.