Search Unity

How to completely clear memory from dictionary of sprites

Discussion in 'Scripting' started by brigas, Mar 26, 2020.

  1. brigas

    brigas

    Joined:
    Oct 4, 2014
    Posts:
    522
    I am using a dictionary of sprites

    Code (CSharp):
    1. Dictionary<string,Sprite> sprdict;
    I am filling it with:

    Code (CSharp):
    1. sprdir.add( spritename, sprite.create( tex, etc..));
    then I am using it to set the tile on a tilemap:

    Code (CSharp):
    1. mastertile.sprite = sprdict[spritename];
    2. tilemap.settile(pos, mastertile);
    Since I am creating these tiles on runtime and I have a lot of different tiles eventually the dictionary gets big and starts taking too much space in memory and has a lot of sprites in memory that are no longer on screen, in a far away part of the map.

    Because of this I wanted to ammend this system to completely clear the dictionary and start creating sprites back from 0.

    So what I am doing at the moment is:
    Code (CSharp):
    1. destroy(tex);
    2.  
    3. foreach( keyvaluepair<string,sprite> obj in sprdict){
    4. destroy(obj.value);
    5. }
    6.  
    7. sprdict= new Dictionary<string,sprite>();
    8.  
    9. GC.collect();
    However as I am tracking the objects in scene in the profiler there is something amiss, there's some kind of overhead I am missing as the objects in scene are not going all the way down back to the starting amount. (ex I start with 500 objects in scene, set some tiles and I go to 8000 objs in scene, I call my destroy method and it goes down to 2000 and when I redraw the tiles this time it goes to 9500 objs in scene.)

    So as I destroy and recreate I end up with more and more objects instead of always having the same count.

    Am I missing something? Is there some other kind of overhead maybe on tilemaps, or do I need to destroy something else? Btw I am using only 1 tile object, just always changing the sprite parameter on it.
     
  2. Dextozz

    Dextozz

    Joined:
    Apr 8, 2018
    Posts:
    493
    Kurt-Dekker likes this.
  3. brigas

    brigas

    Joined:
    Oct 4, 2014
    Posts:
    522
    clearing the dictionary that way doesn't destroy the sprites, I tried it at first but even after garbage collection they are still there

    the sprites dont behave as game objects
     
  4. lordofduct

    lordofduct

    Joined:
    Oct 3, 2011
    Posts:
    8,532
    Honestly the dictionary likely has nothing to do with it cause the dictionary is just holding a pile of references to the sprites which you've cleared out. This could have been a List, a HashSet, and Array, a whatever collection... this false association can lead to a lot of filtered out responses if you've been researching in the context of "dictionary of sprites".

    Something is going on with your creation/destruction of the sprites, and potentially other unmanaged objects.

    You only show pseudo-code, but some of it includes:
    Code (csharp):
    1. sprdir.add( spritename, sprite.create( tex, etc..));
    Code (csharp):
    1. mastertile.sprite = sprdict[spritename];
    2. tilemap.settile(pos, mastertile);
    So this code implies that Sprites, TileMaps, and TileBases are all being created. All 3 of which are unmanaged unity objects.

    Do you recycle these or are you creating a new TileMap and Tiles each time? If you're creating a new TileMap and Tiles each time, are you remembering to destroy the old one as well?

    Are there any other unmanaged objects you're creating? Are you cloning the textures that you make the sprites out of? What else is going on in your code?

    Can you share you actual code and not pseudo-code so we can glean a better understanding of what is actually going on and not your assumptions of what is going on?
     
  5. brigas

    brigas

    Joined:
    Oct 4, 2014
    Posts:
    522
    I only use 1 tile and 1 tilemap, tiles and tilemaps aren't created. The only thing that i do to the tile map is using SetTile() and ClearAllTiles(). Unless SetTile also creates tiles? Maybe that is the issue

    I do create the textures but they are 1024x1024 and I reproduce the problem easily before filling even 1 texture.

    the code is 20k lines long across many scripts so it is too long to post but this is the logic:

    - only 1 tile asset, never cloned
    - only 1 tilemap, never cloned
    - setpixels on texture to create a spritesheet ( 2601 possible sprites per sheet before needing new sheet)
    - use spritesheet to sprite.create, and save the sprite to the dictionary:
    Code (CSharp):
    1. TileSpriteDict.Add(tv, Sprite.Create(texSheetList[SheetCurrentPage], new Rect(0 + SheetCurrentX * imgx + SheetPadding + (SheetPadding * SheetCurrentX), 0 + SheetCurrentY * imgy + SheetPadding + (SheetPadding * SheetCurrentY), imgx, imgy), SprPivot, 128));
    2.  
    -change the sprite parameter on the only tile I have
    Code (CSharp):
    1. MasterTile.sprite =TileSpriteDict[tv];
    -set the tile on the only tilemap I have
    Code (CSharp):
    1. Tilemap.SetTile(pos, MasterTile);
    -eventually clear the tilemap when i want to
    Code (CSharp):
    1. Tilemap.ClearAllTiles();
    So would this be creating tiles in the background without my knowledge?
     
  6. brigas

    brigas

    Joined:
    Oct 4, 2014
    Posts:
    522
    Is there a way to check for unmanaged objects?
     
  7. MartinTilo

    MartinTilo

    Unity Technologies

    Joined:
    Aug 16, 2017
    Posts:
    2,455
    Try inspecting this with the Memory Profiler package and try calling Resources.UnloadUnusedAssets (the GC for unmanaged resources that have been destroyed and no references anymore).
     
    brigas likes this.
  8. brigas

    brigas

    Joined:
    Oct 4, 2014
    Posts:
    522
    Thanks!