Search Unity

Destroying Procedurally Generated Objects

Discussion in 'Scripting' started by fanjules, Jan 28, 2014.

  1. fanjules

    fanjules

    Joined:
    Nov 9, 2011
    Posts:
    167
    A quick post regarding my findings with this, I've googled for clarifications but it's not immediately obvious and the answers are scattered about. I'm also posting here in case I am doing things wrong, or others have additional tips.

    As we know we destroy objects in Unity using the following:

    Code (csharp):
    1. Destroy(myobject);
    However, if we have generated the objects mesh ourselves, we also need to reclaim that memory. This isn't necessary for objects where the mesh is an asset and handled automatically by Unity. To destroy the mesh (assuming you don't want to use it for another object, we use:

    Code (csharp):
    1. Destroy(myobject.GetComponent<MeshFilter>().mesh);
    I have been doing procedurally generated code for a while now, and using the above two lines has worked out fine so far. However, one of my recent projects had objects with their own materials. The materials were not part of my projects assets, they were downloaded from the web or a local file and used once for that object, then discarded. These too need to be destroyed otherwise the memory will never be reclaimed. So:

    Code (csharp):
    1. Destroy(myobject.renderer.material.mainTexture);
    2. Destroy(myobject.renderer.material);
    I'm surprised I hadn't came across the necessity to do this before... in a previous project I nearly did, but instead managed a collection of downloaded textures and materials in a list which was shared amongst all sorts of objects... here there was no need to destroy them with the object.

    But in my new project - where each object had it's own bespoke material - I made the mistake of assuming that Destroy would also release those materials because nothing was using them. These are not garbage collected entities - just like procedurally generated meshes.

    Thankfully, these oversights can be spotted with Unity's profiler.

    Lastly, it's fairly obvious that your calls to Destroy should be in the right order (e.g. you can't destroy an objects material if you have already destroyed the object):

    Code (csharp):
    1. Destroy(myobject.GetComponent<MeshFilter>().mesh);
    2. Destroy(myobject.renderer.material.mainTexture);
    3. Destroy(myobject.renderer.material);
    4. Destroy(myobject);
    Hopefully this will provide useful for some of you and you will get a nice warm feeling knowing you won't be leaking memory - a potentially app-crashing situation on mobile.

    Feel free to post if you have any better ways of doing it, or indeed if you have came across any other "gotcha" cases where you needed to destroy more than just materials and meshes which may not be immediately obvious. Just be careful that this discussion applies only to procedurally generated objects - so don't accidentally destroy things which are in your Resources folder or project assets - this tends not to end well!
     
  2. MikeUpchat

    MikeUpchat

    Joined:
    Sep 24, 2010
    Posts:
    1,056
  3. fanjules

    fanjules

    Joined:
    Nov 9, 2011
    Posts:
    167
    I had seen that, but assumed it applied to assets within the Unity3d project, rather than stuff you had created or loaded in from byte arrays, the web, etc. However, I have checked it and it works fine and merrily goes along removing meshes, textures, materials and presumably anything else that may otherwise be a forgotten chunk of memory.

    However, thoughts on a couple of reasons why you may not want to use this:

    1) The documentation for Resources.UnloadUnusedAssets() suggests it operates by walking the entire heirarchy of objects, components and static variables. In a complex scene - or indeed a project with a lot of scripts - this could be potentially expensive compared to a simple call to Destroy() for individual objects.

    2) If you Destroy() an object but want to retain (for example) it's texture, any calls to Resources.UnloadUnusedAssets() elsewhere in your scripts will remove it from memory, causing the reference to fail? The documentation isn't entirely clear on this, so perhaps if you have stored a reference to those textures or materials then it wouldn't be freed. But if so, then presumably the "walking" of objects and scripts explained above is truly extensive - essentially every variable in every class in every object is examined? Not a problem for simple projects, but for huge scenes could be an issue?

    On the other hand, I also see an advantage of Resources.UnloadUnusedAssets() is that if you make some changes to your procedurally generated objects you don't have to worry about updating or modifying your calls to Destroy()... Resources.UnloadUnusedAssets() should simply remove everything.

    I am wondering what the "best practice" advise is. I can see advantages to both cases, and I also note quite a few people still recommending to destroy procedurally generated meshes manually - but it's hard to know if this is current or out-dated advice.
     
  4. GenericJoe

    GenericJoe

    Joined:
    Apr 27, 2012
    Posts:
    33
    Nice summary, thank you, although I did all of that and my VBO count was still increasing. The only saviour was UnloadUnusedAssets, but that is a heavy function to call.
    Then I found this post: http://forum.unity3d.com/threads/ho...was-created-by-the-combinemesh-script.112093/ and swapped "mesh" to "sharedMesh", et voilà!

    By the way, I'm not using combineMesh or anything like that!