Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Voting for the Unity Awards are OPEN! We’re looking to celebrate creators across games, industry, film, and many more categories. Cast your vote now for all categories
    Dismiss Notice
  3. Dismiss Notice

So...Why is DestroyImmediate not recommended?

Discussion in 'Scripting' started by ArachnidAnimal, Apr 16, 2018.

  1. ArachnidAnimal

    ArachnidAnimal

    Joined:
    Mar 3, 2015
    Posts:
    1,727
    I have read this page 5 times, and I still have not learned why DestroyImmediate is not recommended.
    https://docs.unity3d.com/ScriptReference/Object.DestroyImmediate.html

    All I see is this:
    You are strongly recommended to use Destroy instead.
    In game code you should use Object.Destroy instead

    So does anyone know WHY it is not recommended?

    thanks

    I read other 3rd party internet blogs and all I see is Warning: Use with extreme caution, like we are handling nuclear waste or something, LOL. http://www.unitygeek.com/difference-between-destroy-and-destroyimmediate-unity-functions/
    But I can't find out why it shouldn't be used.
     
    Last edited: Apr 16, 2018
  2. Kiwasi

    Kiwasi

    Joined:
    Dec 5, 2013
    Posts:
    16,860
    DestroyImmediate is not recommended for the following reasons.
    • In the editor it can remove assets, even in playmode. This means a bug in your code can remove prefabs/art/sounds/scenes ect.
    • DestroyImmediate moves the destruction out of the normal script execution order. Which means OnDestroy and OnDisable will be called at unusual times. This can lead to null reference errors, or other more subtle problems.
    Generally the only reason to use DestroyImmediate is in editor code.
     
  3. ArachnidAnimal

    ArachnidAnimal

    Joined:
    Mar 3, 2015
    Posts:
    1,727
    This is a bit mysterious.

    Destroy(gameObject2);
    if (gameObject2)
    {
    Debug.Log("GameObject 2 exists");
    }

    I thought Unity checks to see if the gameObject2 was set to be destroyed when implicitly converting the gameObject to a bool. So the gameObject2 would evaluate to false. Does Unity not do this?
    Because the Debug.Log statement is executing and I thought it wasn't supposed to.


    Even though I shouldn't have any issues with DestroyImmediate in my case, I'll just stick with Destroy just to be safe.
     
  4. Kiwasi

    Kiwasi

    Joined:
    Dec 5, 2013
    Posts:
    16,860
    Destruction happens at the end of the frame. So you can still use a destroyed GameObject as normal until the end of the frame.
     
  5. starikcetin

    starikcetin

    Joined:
    Dec 7, 2017
    Posts:
    335
    Do these null reference errors happen in the engine code or are you referring to possible scripting mistakes?

    Also, I wonder about those subtle problems because I am in a situation where I need to use DestroyImmediate and I want to know if I will regret that in the future.
     
    yong2khoo likes this.
  6. Ryiah

    Ryiah

    Joined:
    Oct 11, 2012
    Posts:
    20,091
    Imagine you have two objects. One of them has just started trying to modify the other and the one it's modifying has just decided to DestroyImmediate. This is the kind of problem he's referring to by null reference errors. With a normal destroy the one that has decided to destroy itself won't do so until all scripts have finished executing and the problem won't occur.

    Yes, you could view this as a scripting "mistake" with the solution being to check if the object exists before you modify it but that's additional processing time that wouldn't have been needed if you just destroyed it normally. That said if you're only going to very occasionally modify the object that will be destroying itself it might not matter.

    What's the situation? We might be able to come up with an alternative to destroying it immediately.
     
    Last edited: Sep 19, 2018
  7. starikcetin

    starikcetin

    Joined:
    Dec 7, 2017
    Posts:
    335
    Well, I wrote myself a small ECS framework which works with components-as-monobehaviours. When I remove a component I broadcast all filter-group pairs that the entity signature is changed and each filter-group checks if the entity fits their requirements.

    But since Destroy call is delayed to the end of the frame, I either need to deviate the ECS world by passing along the removed component type and pretending it is actually not there, or I need to use DestroyImmediate which keeps both worlds in sync without any effort.

    I don't want to deviate the ECS world from the actual gameobjects since, as you can imagine, there can be some nasty inconsistent behaviour if a component exists on a gameobject but ECS world has already declared it removed, for a whole frame.
     
    guneyozsan likes this.
  8. jvo3dc

    jvo3dc

    Joined:
    Oct 11, 2013
    Posts:
    1,520
    I use DestroyImmediate in combination with multi-threading. (Destroy can only be called from the "main thread".)

    The null reference errors can actually also occur in the script that you are destroying. So, this can actually be null and you'll have to check that.
    Code (csharp):
    1.  
    2. if (this == null) return;
    3.  
    Not a very common thing to check.
     
    wanrclhnyd likes this.
  9. Ryiah

    Ryiah

    Joined:
    Oct 11, 2012
    Posts:
    20,091
    If your system is tracking changes and preventing objects from interacting if they no longer meet the requirements of the executing code then you should be fine. At least from other objects belonging to the framework.
     
  10. starikcetin

    starikcetin

    Joined:
    Dec 7, 2017
    Posts:
    335
    So the nullification of references is the only reason why DestroyImmeidate is not recommended, is that correct?
     
    will_unity731 likes this.
  11. Ryiah

    Ryiah

    Joined:
    Oct 11, 2012
    Posts:
    20,091
    That, and the possibility that you might end up destroying assets permanently. There might be a performance overhead too based on some of the other posts I've read but I haven't dug too deeply into it.
     
    starikcetin likes this.
  12. Kiwasi

    Kiwasi

    Joined:
    Dec 5, 2013
    Posts:
    16,860
    This would be the bigger concern with calling DestroyImmediate in game code. Accidentally call it on the wrong thing and you've just deleted some key asset from your project. That's why I prefer to use DestroyImmediate in editor code.
     
  13. starikcetin

    starikcetin

    Joined:
    Dec 7, 2017
    Posts:
    335
    I use Git so destroying assets wouldn't be a problem. I will look into the performance hit. Thanks for the help.
     
    will_unity731 likes this.
  14. IgorZ

    IgorZ

    Joined:
    Jan 2, 2017
    Posts:
    1
    In my project I've ended up in a race condition situation: I needed the object to immediately leave hierarchy and stop any physical behavior, and I couldn't call `DestroyImmediate`. After some trial and error, I've ended up with the following solution:
    Code (CSharp):
    1.   public static void SafeDestory(GameObject obj) {
    2.     obj.transform.parent = null;
    3.     obj.name = "$disposed";
    4.     UnityEngine.Object.Destroy(obj);
    5.     obj.SetActive(false);
    6.   }
    7.  
    The object, deleted like this, will stop triggering any physics immediately. And it won't be found in the hierarchy by the methods that do such a lookup. And this method can be called from any callback, event from `FixedUpdate`.
     
  15. Baylamon

    Baylamon

    Joined:
    May 16, 2019
    Posts:
    13
    I had another issue where Destroyimmediate caused issues. Running through a list of game objects the list changed during the processing.
    Code (CSharp):
    1.             foreach (Transform object in this.transform)
    2.             {
    3.                 if (object is anything)
    4.                 {
    5.                     Destroyimmediate(object.gameObject);
    6.                 }
    7.             }
    Just take care, the enumeration is changed nullifying an object.
     
    Kiwasi likes this.
  16. craig4android

    craig4android

    Joined:
    May 8, 2019
    Posts:
    124
    actually I prefer DestroyImmediate over Destroy since I want to make sure that the Object gets removed from hierarchy within in the very same Frame.

    However I'm scared to use it now. But actually there shouldn't happen anything unless I'm looping through a collection containing the destroyed Object as I'm destroying it? Or am I missing something?
     
  17. Baylamon

    Baylamon

    Joined:
    May 16, 2019
    Posts:
    13
    As long as you have a single object in the list to destroy it's fine. But looking for multiple objects you have to take into consideration the list was altered with the first destroyed object.
     
  18. SparrowGS

    SparrowGS

    Joined:
    Apr 6, 2017
    Posts:
    2,536
    To go over a collection you're modifing just go from the end of the collection to the start ( i=collection.Length/Count ; i--).

    That said, don't use DestroyImmideate unless you're making editor code and the compiler tells you to.
     
  19. nasos_333

    nasos_333

    Joined:
    Feb 13, 2013
    Posts:
    12,870
    I want to destroy objects within a while loop in update, if i dont use immediate the wrong object may be destroyed, as i mark for destruction a object i iterate ots shape at loop start, but due to destroy delay, maybe destroyed after the new correct object has been created.

    So i think destroy cant be used reliably in this case
     
  20. Antypodish

    Antypodish

    Joined:
    Apr 29, 2014
    Posts:
    10,558
    5his is rather necro. Probably would be better having separate thread.

    But,
    You can ache your objects that need to be destroyed. For example into dictionary, array, or list.
    Then work on that collection, to destroy relevant objects.
     
    nasos_333 likes this.
  21. nasos_333

    nasos_333

    Joined:
    Feb 13, 2013
    Posts:
    12,870
    thanks
     
  22. Jamez0r

    Jamez0r

    Joined:
    Jul 29, 2019
    Posts:
    200
    Alright, I've got a relevant question - My game has Singleplayer and Multiplayer. There are certain parts of the Scenes that need to look differently in Singleplayer than in Multiplayer. My solution is to create "Container Gameobjects" that I place the things that are unique to either Singleplayer/Multiplayer as its children, and then I add a Script to the Container GameObjects that automatically destroys itself in Awake() if you are in the other gamemode. So if you run the game and select Multiplayer, then when it loads a Scene, any [Singleplayer Container] gameobject would destroy itself.

    The problem with using Destroy() in Awake() is that Awake() is still called on all of the gameobjects that are inside of the container. If I use DestroyImmediate() on the Container in Awake() (and set its Script Execution Order to happen before everything else) then the children gameobjects do not call Awake().

    Is there any way to use Destroy(), but also prevent the child gameobjects from having Awake() called on them?

    Thanks for any help!

    (Also just FYI, I know that another way to handle this would be to only instantiate the Singleplayer-stuff when the game is started in Singleplayer, but that doesn't work well when designing the maps. We need to be able to see how everything looks in edit mode when setting up the scene, so being able to just enable/disable these Container Gameobjects seems to be the best solution)
     
  23. Kiwasi

    Kiwasi

    Joined:
    Dec 5, 2013
    Posts:
    16,860
    From memory awake isn't called on disabled GameObjects.

    However I would build your whole system differently. Instead of destroying GameObjects you don't need, instantiate the GameObjects you do need. This is pretty much what the prefab system is built for.
     
    Jamez0r and Joe-Censored like this.
  24. Jamez0r

    Jamez0r

    Joined:
    Jul 29, 2019
    Posts:
    200
    Thanks Kiwasi - I didn't realize that if I disabled the Container in its Awake() function, that it wouldn't call Awake() on the children (note that the script on my Container has its Script Execution Order set to process earlier than all my other scripts). I assumed that the Awake() calls were queued up for that frame. I just tested it out, and you are indeed correct, and that will work great for my situation!

    Appreciate it!