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. Dismiss Notice

Having some issues with memory and garbage collection

Discussion in 'Scripting' started by benjammin1391, Mar 11, 2015.

  1. benjammin1391

    benjammin1391

    Joined:
    Feb 10, 2015
    Posts:
    17
    I have some code that I use to generate a 2d Tile map. What the code does is generate a number of large meshes with textures (each texture is the size limit that Unity allows)

    This happens every time the world is generated,a nd it works fine. Once. if I ever try to regenerate the world Unity crashes with an out of memory error.

    Now, the regenerate world method does destroy all of the old objects before I create new ones...supposedly. In practice it doesn't seem to work because Unity keeps running out of memory.

    So how can I improve it? How can I totally destroy all the objects I need destroyed? DestroyImmidiate() is NOT working.

    I also still get the message about cleaning up leaked objects even after trying to destroy them all.

    here is my destroy method:
    Code (CSharp):
    1.  
    2. public override void OnInspectorGUI()
    3.     {
    4.        // base.OnInspectorGUI();
    5.         DrawDefaultInspector();
    6.         if (GUILayout.Button("Regenerate"))
    7.         {
    8.             GameObject[] Resources = GameObject.FindGameObjectsWithTag("Resource");
    9.             foreach (GameObject g in Resources)
    10.                 DestroyImmediate(g);
    11.             GameObject[] maps = GameObject.FindGameObjectsWithTag("Map");
    12.             foreach (GameObject g in maps)
    13.                 DestroyImmediate(g);
    14.             WorldGenerator tm = (WorldGenerator)target;
    15.             tm.buildWorld();
    16.         }
    17.         if (GUILayout.Button("Destroy All"))
    18.         {
    19.             GameObject[] Resources = GameObject.FindGameObjectsWithTag("Resource");
    20.             foreach (GameObject g in Resources)
    21.                 DestroyImmediate(g);
    22.             GameObject[] maps = GameObject.FindGameObjectsWithTag("Map");
    23.             foreach (GameObject g in maps)
    24.                 DestroyImmediate(g);
    25.         }
    26.         if (GUILayout.Button("Clear Objects"))
    27.         {
    28.             GameObject[] Resources = GameObject.FindGameObjectsWithTag("Resource");
    29.             foreach (GameObject g in Resources)
    30.                 DestroyImmediate(g);
    31.         }
    32.     }
    33.  
     
  2. xanat0s

    xanat0s

    Joined:
    Nov 20, 2014
    Posts:
    10
    Well, right off the bat I'm seeing one potentially major issue. You should not be iterating over an array and destroying the objects you are iterating over. This is not good (in programming in general.)

    Is there a specific reason you need to explicitly destroy these objects as opposed to caching them?
     
  3. benjammin1391

    benjammin1391

    Joined:
    Feb 10, 2015
    Posts:
    17
    Its just for testing purposes.

    The world is randomly generated, every texture as well as every single resource. So when I make tweaks to the world generation I need to completely rebuild everything. I cant simply re-purpose objects because there is a varied amount of them all every time the world is built.

    In the final game the maps will never actually be destroyed, unless the player destroys their save file of course. But for rapid testing and retesting it would be nice to simply be able to wipe the slate and build again.
     
  4. Kiwasi

    Kiwasi

    Joined:
    Dec 5, 2013
    Posts:
    16,860
    Consider using a coroutine. Also consider calling GC.Collect manually (may or may not make a difference).

    Something like

    Destroy everything, wait 2 frames, call GC.Collect, wait 2 frames, regenerate your world.

    Also go for a standard for loop instead of foreach.
     
  5. benjammin1391

    benjammin1391

    Joined:
    Feb 10, 2015
    Posts:
    17
    Sorry if this a dumb question, but whats a coroutine?
     
  6. Kiwasi

    Kiwasi

    Joined:
    Dec 5, 2013
    Posts:
    16,860
  7. xanat0s

    xanat0s

    Joined:
    Nov 20, 2014
    Posts:
    10
    This may not be the ideal way to go about it. Firstly, in Unity, it's only going to applicable with Mono objects, not Unity objects. Secondly, in general, Collect() makes absolutely no guarantee that all inaccessible memory is going to be reclaimed.

    Edit:
    In regards to manual Garbage Collection:

    Rule #1

    Don't.

    This is really the most important rule. It's fair to say that most usages of GC.Collect() are a bad idea and I went into that in some detail in the orginal posting so I won't repeat all that here. So let's move on to...

    Rule #2

    Consider calling GC.Collect() if some non-recurring event has just happened and this event is highly likely to have caused a lot of old objects to die.

    A classic example of this is if you're writing a client application and you display a very large and complicated form that has a lot of data associated with it. Your user has just interacted with this form potentially creating some large objects... things like XML documents, or a large DataSet or two. When the form closes these objects are dead and so GC.Collect() will reclaim the memory associated with them...

    So it sounds like this situation may fall under Rule #2, you know that there's a moment in time where a lot of old objects have died, and it's non-recurring. However, don't forget Rico's parting words.

    Rule #1 should trump Rule #2 without strong evidence.

    Source - http://blogs.msdn.com/ricom/archive/2004/11/29/271829.aspx
     
  8. benjammin1391

    benjammin1391

    Joined:
    Feb 10, 2015
    Posts:
    17
    Ah, thats useful to know thanks!

    Im not sure it'll work for what Im trying to do though. The whole destroying and rebuilding terrain is supposed to be done through the Editor, not at any point during the actual game. (The game will simply build the terrain once and be done)

    So can I use a coroutine in an editor only method? I was that it had to be declared inside the Update method...
     
  9. Kiwasi

    Kiwasi

    Joined:
    Dec 5, 2013
    Posts:
    16,860
    That's a good question. I actually don't know the answer. But I suspect you can't.

    The general idea was to give Unity the time to clean up before starting building the new terrain.

    So GC.Collect might work. Or as indicated by @xanat0s it might be a harebrained scheme.

    Another quick question, are you using the 64 bit editor? This should be more then able to cope with most memory requirements, if your physical memory and paging file is big enough.
     
  10. ThermalFusion

    ThermalFusion

    Joined:
    May 1, 2011
    Posts:
    906
    If you are creating textures you need to destroy these aswell.
     
  11. Pawscal

    Pawscal

    Joined:
    Mar 26, 2013
    Posts:
    11
  12. benjammin1391

    benjammin1391

    Joined:
    Feb 10, 2015
    Posts:
    17
    Not yet. I use an imaged machine and the image hasnt been updated with 5 yet. Thats happening this weekend. Im stuck on 4.6 for now.

    I thought it was doing that. If thats not the case then yeah that will solve a bunch of problems.

    Now that I like. Thanks! E: Damn it, that didnt work.
     
    Last edited: Mar 12, 2015
  13. ThermalFusion

    ThermalFusion

    Joined:
    May 1, 2011
    Posts:
    906
    Any unity asset like Texture,Mesh or Material will need to be destroyed manually, GC does not govern these. If unity complains about cleaning up leaked things you need to destroy these yourself.