Search Unity

Bug Sudden slowdown of inspector drawing. Serializing every editor frame. 2022.1.4f1

Discussion in 'Scripting' started by Darkgaze, Aug 31, 2022.

  1. Darkgaze

    Darkgaze

    Joined:
    Apr 3, 2017
    Posts:
    397
    I hit a button that triggers a huge process on Editor. After that the scene is dirtied and needs to be saved in order to have that new data serialized.

    The component where that button is placed is opened during the whole process. Right after finishing the process I get a 260ms / 1fps slowdown and seems like it keeps calling serialization several times while trying to draw the inspector, specifically trying to draw the title bar. The whole editor stalls to a 1fps update.

    I'm serializing a huge float array in the scene which has [HideInInspector], but seems like the inspector ignores that and manages that array even though it doesn't have to be drawn. If I delete that serialized field, everything is fast... Saving the scene doesn't help... (I know, I'm not using Scriptable objects, I can't in this case, but I wonder why this happens)

    The problem stops when you deselect the object. but comes back when you select it again.

    upload_2022-8-31_16-54-51.png

    So my questions are:

    - Why is it calling serializedObject.Update() several times when trying to draw the inspector headers?

    - Why is HideInEditor being ignored when managing the data? it is slower to draw this editor than others, so it is related to this data being managed somehow.

    I use Odin Inspector. Doesn't seem like it is related, but who knows.
     
    Last edited: Aug 31, 2022
  2. bjarkeck

    bjarkeck

    Joined:
    Oct 26, 2014
    Posts:
    301
    You can toggle Odin drawing completely on and off in "Tools > Odin > Preferences > Editor Types" and test whether Odin is causing the object to re-serialize every frame in the inspector. If it turns out it is Odin, then first, make sure you're on the latest version, and if it still Odin after that, then it would be awesome with an example project or unitypackage that reproduces this behaviour. :D
     
  3. Darkgaze

    Darkgaze

    Joined:
    Apr 3, 2017
    Posts:
    397
    I asked in the Odin Discord. seems like this is something on Unity's side. But something weird.

    I update the data via that Odin button. But no .ApplyModifiedProperties is called. So the data stays lingering.

    Seems like Unity calls a serialization Update every frame. Odin tries to avoid that as much as possible, but if you changed the data, it's trying to serialize every time it's trying to draw.


    The question here is.... WHY doesn't it serialize the data in the first call and the next ones are faster?





    [Edit] In fact, I tested creating a Custom editor for that component. I call the big process and then serializedObject.ApplyModifiedProperties(); This doesn't happen anymore.
    Seriously confusing. Saving the scene doesn't help either. Why isn't it serializing the data??
     
  4. bjarkeck

    bjarkeck

    Joined:
    Oct 26, 2014
    Posts:
    301
    So, let me know if I got this right.
    Unity doesn't update the inspector every frame, but as soon as you apply your data, it does?

    What happens if you duplicate the object?
     
  5. Darkgaze

    Darkgaze

    Joined:
    Apr 3, 2017
    Posts:
    397
    I talked with the people from Odin. Somebody said that Unity calls Update() to the serialized objects it is displaying, EVERY editor frame.
    Everytime it tries to draw that header, that calls the rest of the items of the UI.

    So if the Update takes time, in my case, because it contains a big array data, it just slows down the whole UI. And they say there's no way to avoid this.... Confusing...

    Apparently there's a way making your own custom editor to update only if needed. No way to do this if I create a button that changes the values with Odin and without a custom editor.
     
  6. warpfx

    warpfx

    Joined:
    Feb 10, 2020
    Posts:
    14
    In order to serialize bigger structures I recommend making a separate component just for data:

    Code (CSharp):
    1. [AddComponentMenu(""), ExecuteInEditMode]
    2. public class MyDataComponent : MonoBehaviour {
    3.     public MyData Data;
    4.  
    5.     void Awake()
    6.     {
    7.         if (Data == null)
    8.             Data = new MyData();
    9.  
    10.         // Our component won't be visible/editable in the Inspector. This probably need to be applied in the CustomEditor of MyComponent or instead it will be visible when selecting the Prefab.
    11.         hideFlags = HideFlags.HideInInspector | HideFlags.HideInHierarchy | HideFlags.NotEditable;
    12.     }
    13. }

    and require that data component in base component:

    Code (CSharp):
    1. [AddComponentMenu("MyCompany/MyComponent"), ExecuteInEditMode]
    2. [RequireComponent(typeof(MyDataComponent))]
    3. public class MyComponent : MonoBehaviour {
    4.     private MyDataComponent _myDataComponent;
    5.     private MyData _data => _myDataComponent.Data;
    6.  
    7.     void Awake()
    8.     {
    9.         _myDataComponent = GetComponent<MyDataComponent>();
    10.     }
    11.  
    12.     void ModifyData() {
    13.         Modify(_data); // Our custom method modifying the data.
    14.         EditorUtility.SetDirty(this); // Will make our MyDataComponent dirty as well.
    15.     }
    16. }
    17.  
    I spent three days in order to find this is the only way to store bigger data and don't overload
    OnInspectorGUI()
    with its
    SerializedObject.Update()
    bombing 10 times per second.

    @Darkgaze

    Apparently there's a way making your own custom editor to update only if needed. No way to do this if I create a button that changes the values with Odin and without a custom editor.


    Creating custom editor won't help with Inspector doing serialization on each frame/10 times per frame. If you found better way to solve the problem then please shout me!

    Tags for Google:

    Slow Unity Inspector. Lagging Unity Inspector. Unity Slow Serialization. Unity Serialize Bigger Object. Serialize Bigger Data. Serialize Big Structures. ISerializationCallbackReceiver called too many times. SerializedObject.Update() called too many times. Called once and once.
     
    Last edited: Dec 19, 2022
  7. Baste

    Baste

    Joined:
    Jan 24, 2013
    Posts:
    6,336
    Unity's default inspector works by doing SerializedObject.Update, then drawing all the fields, then doing SerializedObject.ApplyModifiedProperties.

    Adding [HideInInspector] doesn't change the data getting update or serialized. In you want Unity to stop managing that huge float array, you'll have to mark it as [NonSerialized].


    If you have to have the array serialized, and you can't put the data in a ScriptableObject (in the asset folder or in the scene), you could try to do a custom inspector with:

    Code (csharp):
    1. //Skip this: serializedObject.Update();
    2. DrawDefaultInspector();
    3. serializedObject.ApplyModifiedProperties();
    And then whenever you're making a modification to the actual data behind the scenes (ie if you press a button that updates the array or whatever), you call serializedObject.Update. What Update does is to copy the data from your scene instance to the serializedObject, so if you have full control over when that happens (harder than it sounds!), it's a possible approach.
     
    AnimalMan likes this.
  8. warpfx

    warpfx

    Joined:
    Feb 10, 2020
    Posts:
    14
    Thanks for response!

    I wasn't doing any
    serializedObject.Update()
    as it looks like Unity's Inspector is doing it by itself. In my [CustomEditor] I could just leave
    OnInspectorGUI()
    empty and it will already make Inspector sluggish. Just because my component has serializable List with 10k objects.

    My solution with creating separate component for data works and I think I have already tried all other ways. Or maybe I overlooked something? I'll later do proof-of-concept project so we can test if there is any better way of serializing bigger structures inlined to the object. I just don't want to create separate asset file if I already have Model component and this object could be converted into Prefab, so it won't make Scene file big as hell.
     
  9. spiney199

    spiney199

    Joined:
    Feb 11, 2021
    Posts:
    7,923
    This topic of 'big data' slowing down the inspector comes up a lot. One effective method is to make an interface between yourself and the serialised assets themselves.

    Even something as simple as an editor window that lets you edit the data and then manually serialise and save the data should work.

    I've seen instances where the large amounts of data are serialised as a binary asset too, so that Unity won't try to serialised the asset.
     
    Bunny83 likes this.
  10. Bunny83

    Bunny83

    Joined:
    Oct 18, 2010
    Posts:
    3,998
    Right. Binary data can even have the advantage that you could only partially load the relevant data (seek to an absolute offset in a file) and only show UI for that data. Essentially make a virtual view for the data. I did this for a custom in game console using the old IMGUI system. It had no issues with 10k or 100k or 1M log entries since only about 20 were shown at a time. It worked extremely well, even on older android devices and this was 10 years ago :)
     
    spiney199 likes this.