Search Unity

Best usage of SerializeField

Discussion in 'Editor & General Support' started by sam_paladin, Jan 24, 2022.

  1. sam_paladin

    sam_paladin

    Joined:
    Oct 5, 2021
    Posts:
    12
    What's the best way to use this in order to take care of the memory usage? Let's say you want to create an Asset Swapper (like an overrider) in game that whenever actions happen then it will destroy some prefabs and instantiate others.

    Let's say you have 100 gameobjects with a script that does this swap. And this script has 4 versions of a prefab, something like this:

    AssetSwapper : Monobehavior

    [SerializeField] private GameObject prefab1;
    [SerializeField] private GameObject prefab2;
    [SerializeField] private GameObject prefab3;
    [SerializeField] private GameObject prefab4;

    Does that mean that for every gameobject when they are created or the event happens, it also loads internally the 4 prefabs even 3 of them might not be used in game? what's the best way of NOT doing that?

    Maybe I am doing something wrong but if I do a quick test I see in the Profiler that this is the case with the mesh filter on the prefabs. I am using old AssetBundles and I keep them in different ones just to make them separated.

    Thanks, Regards.
     
  2. MartinTilo

    MartinTilo

    Unity Technologies

    Joined:
    Aug 16, 2017
    Posts:
    2,456
    Yes and no.
    Yes it loads all 4 prefabs, even if not used. But only once. Each GameObject then holds a pointer to these same 4 prefabs. (Memory usage per pointer is sizeof(long) on x64)

    If you want to reduce the size for each object by reducing that from 4 pointer values to 1 per object, you could have them all referencing a central swapper, possibly a singleton, that holds these for them

    That's not gonna be much in terms of memory savings though, only a few byte.

    If you want to not have these assets loaded unless they are needed, you'll need to not have pointers to them assigned in the editor. Instead you'll have to have some logic by which to identify their asset bundle, make sure it is loaded and load the prefab from there. For example be referencing via their name, as string. Now string comes with more memory usage than just the pointer to the string and is very prone to breaking and setting up that loading logic is some boilerplate code you don't need to write because: Addressable basically does this in a more optimised, simplified and less error prone way out of the box so you should consider using that instead.
     
  3. sam_paladin

    sam_paladin

    Joined:
    Oct 5, 2021
    Posts:
    12
    Note: we are not using the new addressables we have a weird Asset bundles old style management that relies on Asset Bundles.

    So our AssetReference goes like this:

    Code (CSharp):
    1. AssetReferenceGameObject : AssetReference<GameObject>
    And that AssetReference:

    Code (CSharp):
    1. public abstract class AssetReference<T> : AssetReference, IAssetReference<T> where T : Object
    And:

    Code (CSharp):
    1. public class AssetReference : IEquatable<AssetReference>
    And this one contains all the AssetBundles calls.

    So what I am holding into my asset swapper is a reference to a scriptable object that holds that 4 references and that scriptable is the one assigned into the editor. Since it's an object I guess it also gets loaded into memory am I right? even if it's by the scriptable.

    I guess, even having x100 scene objects event swapper into scene with 4 prefabs each one the worst case scenario is to have them just 4 times once if I read correctly no? is not that dramatic I guess...

    Thanks, Regards.
     
  4. MartinTilo

    MartinTilo

    Unity Technologies

    Joined:
    Aug 16, 2017
    Posts:
    2,456
    If a reference is assigned in the editor via the inspector and it's directly to a field of a type inheriting from UnityEngine.Object, then yes, that reference will always mean that the referenced object is loaded into memory when the referencing object is loaded into memory.
    And the chain goes on from there, so unless your ScriptableObject is using your AssetReferenceGameObject or similar for the prefabs, they are loaded in as well. And so are any other assets like textures etc that these prefabs need.

    But if I followed your explanations correctly then no, I don't think there is much of a memory overhead here.
     
    sam_paladin likes this.
  5. sam_paladin

    sam_paladin

    Joined:
    Oct 5, 2021
    Posts:
    12
    So can we confirm this is good enough?

    My scriptable is using AssetReferenceGameObject as a Serialised field in a form of a list:

    Code (CSharp):
    1.     [SerializeField]
    2.     private List<DummyClassExample> list;
    3.  
    4.     [Serializable]
    5.     public class DummyClassExample
    6.     {
    7.         public int exampleInt;
    8.         public AssetReferenceGameObject asset;
    9.     }
    Thanks, Regards.
     
  6. MartinTilo

    MartinTilo

    Unity Technologies

    Joined:
    Aug 16, 2017
    Posts:
    2,456
    Yep can confirm. That should do it :)
     
    sam_paladin likes this.