#Memory issues

1 messages Β· Page 1 of 1 (latest)

fast jungle
#

Just continuing a discussion with @frail fog about loading all sprites at game start up...

#

Just been fiddling around and if you move a room atlas to a "Resources" folder in the room directory and untick "Include in build", it won't be loaded into sharedassets0 (and therefore I assume not loaded into memory on startup)

#

There's a callback when a sprite tries to load from the atlas that you can tap into to lazy-load the resource. So sticking this in PowerQuest works-

    void OnEnable()
    {
        UnityEngine.U2D.SpriteAtlasManager.atlasRequested += RequestAtlas;
    }

    void OnDisable()
    {
        UnityEngine.U2D.SpriteAtlasManager.atlasRequested -= RequestAtlas;
    }

    void RequestAtlas(string tag, System.Action<UnityEngine.U2D.SpriteAtlas> callback)
    {
        Debug.Log("Requested atlas: "+tag);        
        UnityEngine.U2D.SpriteAtlas atlas = Resources.Load<UnityEngine.U2D.SpriteAtlas>(tag);            
        if ( atlas )
        {
            Debug.Log("Found atlas");
            callback(atlas);
        }
        else 
        {
            Debug.Log("Failed to find atlas");
        }
        //callback(sa);
    }```
#

Then you'd also need to unload the resource on room exit

#

But that's a pretty quick simple fix. (if it actually works in memory, and doesn't cause horrible load times between rooms)

#

To optimize room load speed you could do a Resources.LoadAsync as soon as ChangeRoom is called, so its loading in BG while the scene is fading out

#

Comparison of build files with one of my rooms set up with a 40mb atlas in the resources folder as a test

fast jungle
#

I'll stop fiddling with this now, but did a bit more first-

With the above code, in builds (not in editor) it requests all assets up-front. So you have to store the callbacks and call them when you've actually loaded the texture (ie. on room load)

I tested this like quickly like this-

        Dictionary<string, System.Action<SpriteAtlas>> m_roomAtlasCallbacks = new Dictionary<string, System.Action<SpriteAtlas>>();


    SpriteAtlas m_lastAtlas = null;
    void LoadAtlas(string roomName)
    {
        // Load atlas
        string atlasName = $"Room{roomName}Atlas";
        System.Action<SpriteAtlas> callback;
        if ( m_roomAtlasCallbacks.TryGetValue(atlasName, out callback) )        
        {
            SpriteAtlas atlas = Resources.Load<SpriteAtlas>(atlasName);
            if ( atlas )
            {
                if ( m_lastAtlas != null )
                {
                    Debug.Log("Unloading atlas "+m_lastAtlas);    
                    Resources.UnloadAsset(m_lastAtlas);                        
                }
                m_lastAtlas = atlas;
                Debug.Log("Loaded atlas "+atlasName);
                callback(atlas);
            }
            else 
            {
                Debug.Log("Failed to find atlas "+atlasName);
            }
        }
    }

    void RequestAtlas(string tag, System.Action<SpriteAtlas> callback)
    {
        m_roomAtlasCallbacks.Add(tag,callback);

    if ( m_currentRoom != null && tag.Equals($"Room{m_currentRoom.ScriptName}Atlas") )
        LoadAtlas(m_currentRoom.ScriptName);
    }```
#

And in LoadRoomSequence(...):

    LoadAtlas(room.ScriptName);```
#

And that seems to kinda work, in the build I can see memory going up when you change rooms in the profiler in builds now.

But leaving a room the memory doesn't drop down again... Can't tell if its not actually unloading the atlas textures or if I'm just not profiling correctly.

frail fog
#

oh, many thanks, you've gone above and beyond as usual!

#

I'll give it a try soon, see what happens with those or try to find something similar if it doesn't work

#

first casualty of this was WebGL builds, which seem to be the more impacted, but I'm also assuming Switch is also dead at this point, been a while since I tested it

verbal sable
#

Good to see that there is a workaround for this - I queried this very early on in PowerQuest

verbal sable
#

@fast jungle has there been updates to this at all? just curious

fast jungle
#

Nope

#

Next step if you want to poke around is seeing if/when unity will unload the data

verbal sable
#

a nice simple answer - i'll play around with it a bit and compare the profiles of road to nowhere on it considering how much ram it uses.

verbal sable
#

i used chatgpt 4 to write a routine.. how does this look - i haven't tested it yet

#

To make PowerQuest unload sprite atlases that are not referenced on a scene change, you'll need to modify the PowerQuest scripts to manage the sprite atlases manually. Here's a step-by-step guide:

  1. Modify the PowerSpriteAtlases.cs script Open the "PowerSpriteAtlases.cs" script in the PowerQuest/Scripts/Editor folder. Add a new method to unload a sprite atlas:

csharp

public void UnloadAtlas(string atlasName)
{
    if (m_atlases == null || m_atlases.Count <= 0)
        return;

    for (int i = 0; i < m_atlases.Count; ++i)
    {
        if (m_atlases[i].name == atlasName)
        {
            Resources.UnloadAsset(m_atlases[i]);
            m_atlases.RemoveAt(i);
            break;
        }
    }
}
#
  1. Modify the QuestScript.cs Open the "QuestScript.cs" script and locate the "OnLoadRoom()" method. Add a new line at the start of this method to call a new function that will unload unused sprite atlases:

csharp

public override IEnumerator OnLoadRoom(string previousRoom, string newRoom)
{
    // Add this line
    UnloadUnusedAtlases(previousRoom);

    // The rest of the existing method code
    ...
}
#
  1. Add the UnloadUnusedAtlases method Add a new method to unload unused sprite atlases when changing rooms:

csharp

private void UnloadUnusedAtlases(string previousRoom)
{
    Room oldRoom = PowerQuest.Get.GetRoom(previousRoom);
    Room newRoom = PowerQuest.Get.GetRoom(newRoom);

    if (oldRoom == null || newRoom == null)
        return;

    List<string> oldRoomAtlases = oldRoom.GetSpriteAtlases();
    List<string> newRoomAtlases = newRoom.GetSpriteAtlases();

    foreach (string atlasName in oldRoomAtlases)
    {
        if (!newRoomAtlases.Contains(atlasName))
        {
            PowerQuest.Get.GetSpriteAtlases().UnloadAtlas(atlasName);
        }
    }
}
#
  1. Add GetSpriteAtlases method to Room.cs Open the "Room.cs" script and add a new method to get a list of sprite atlases used in the room:

csharp

public List<string> GetSpriteAtlases()
{
    List<string> spriteAtlases = new List<string>();
    SpriteRenderer[] spriteRenderers = GetComponentsInChildren<SpriteRenderer>(true);

    foreach (SpriteRenderer spriteRenderer in spriteRenderers)
    {
        if (spriteRenderer.sprite != null && !spriteAtlases.Contains(spriteRenderer.sprite.texture.name))
        {
            spriteAtlases.Add(spriteRenderer.sprite.texture.name);
        }
    }

    return spriteAtlases;
}
#

Now, PowerQuest will unload sprite atlases that are not referenced in the new room when changing rooms. Note that this assumes that sprite atlases are named after their corresponding textures. This may cause issues if you have other elements in your game that share sprite atlases with the rooms, so be sure to test your game thoroughly and handle any edge cases that may arise due to the change in loading behavior.

frail fog
#

@fast jungle I'm coming back to this, and I had an idea that might or might not be "proper". What if I remove the Room prefabs array from the PQ object? Not sure if you're only using it to find rooms or to iterate over them for certain things, but I'm guessing that if there is no link to them, none of the sprite atlases & related objects for them will be loaded, then the code that's using that array can maybe use some reflection to deal with the rooms...

fast jungle
#

That would be the way to separate it properly, yeah

#

But also non-trivial.

frail fog
#

my second name is NonTrivial

fast jungle
#

πŸ™‚

#

Are you running out of mem because of rooms?

frail fog
#

I know, this is going to be maybe a lot of work, but I also would like to have a "clean" solution, without having to deal with Resources, ideally...

frail fog
fast jungle
#

Oh yaay

frail fog
#

it's crashing while loading audio, some FMOD code is crashing while reallocating memory, but I think it's a red herring

#

(this is on Switch btw)

fast jungle
#

Have you put your atlases in resources?

frail fog
#

nope, but that's what I want to avoid, having manual steps and all that, but you're right, I should maybe try that first πŸ™‚

fast jungle
#

If that doesn't work then separating rooms correctly won't help either afaik

frail fog
#

ah, right

#

well, rooms are linked to more things than just sprites, so that was my thinking

fast jungle
#

It only takes a sec to move them

#

But you might not have the Atlas loading code that's in 0.16

frail fog
#

ok, so just the atlas itself, or also the sprites?

fast jungle
#

Yeah

frail fog
#

nope, I'm still on 0.15 or something like that

fast jungle
#

The sprites aren't built into the game, just the atlases

#

(unless unity is doing something really silly)

frail fog
#

I know, but not sure what Unity will do when you only move the spriteatlas file

#

in any case, I guess that should be easy to find out

fast jungle
#

Yeah, I just made a resources folder in each room and dragn the Atlas into it, and untick "include in build"

#

Then in the latest beta you can hopefully find the code I used to load them. It's a unity callback and a couple of functions in PowerQuest.cs I thiiink

#

But the issue I have is I don't know how to unload them again

frail fog
#

ah, right...

fast jungle
#

But I didn't look very hard

frail fog
#

do you know what file is the one that should hold those Resources in the packaged build?

#

I'm assuming it should be resources.assets or resources.assets.resS

fast jungle
#

Yeah. One of those I think. But not sure off the top of my head

frail fog
#

no worries, is just that I can't find any info, but I'll keep trying

#

just trying to confirm that moving stuff worked πŸ™‚

#

I'm not even trying to load them just moving them around and building for now

fast jungle
#

I just moved stuff into resources and checked which got bigger when I was experimenting πŸ˜›

frail fog
#

hehe, right

#

I might have another issue I think, because one of those sharedAsset files got bigger than what Unity says it's valid (4GB, mine is 5GB) so that might also be causing the crash...

fast jungle
#

That's probably the one that's loading at startup

frail fog
#

yeah, it's the one that FMOD is trying to load, but still not sure what's it trying to do (all my music is Streaming)

#

in any case, let's see if this Resources stuff fixes that

fast jungle
#

If you put room atlases in resources, they should all be invisible but the game should still load. So can quickly test if that makes the difference you need

frail fog
#

yep, that's what I'm trying right now, don't care if it doesn't work, but at least should load πŸ™‚

strange plume
#

Do you have FMOD .bank files in the StreamingAssets folder?

frail fog
#

nope, don't use FMOD myself, it's just whatever Unity is doing under the covers πŸ™‚

strange plume
#

Ah okay, was going to say that they can get pretty large!

frail fog
#

it takes around 10 minutes to build the game each time, fun...

frail fog
#

it now crashes on a separate part, so I guess that did something πŸ˜„

frail fog
fast jungle
#

Yeah I'm doing that. But memory doesn't drop when I do (in windows explorer) so don't know if it's actually freeing them

frail fog
#

oh, that's not very useful then πŸ˜‚

fast jungle
#

That's basically where I got up to when I stopped. Didn't look into it any more than that

frail fog
#

right

flint apex
#

Hi, im hitting this issue. is this all the current information on this? im not able to update to 0.16, so i gotta make these changes manually

fast jungle
#

Yeah I haven't looked at it since. You can look at the changes in 0.16, and migrate across what you need. But it was just early tests from me.

#

The easiest thing you can do is look at your compression settings on atlases though, if you haven't already

flint apex
#

yeah, i cant really change those if avoidable.
i take it the unloading wasnt solved yet? (just so i dont lose time looking for it)

fast jungle
#

I just don't know if it'll unload them or not. Afaik Unity allocates chunks of memory as needed and then deallocates in stages when it decides it's not needed any more. No idea when that would happen son would involve a lot more testing/tesearch to figure out

#

Potentially you could load room by room and just find places in the game to do a full reload (eg go to an empty scene, then back to the next part of the game). Maybe something like that would work?