#Memory issues
1 messages Β· Page 1 of 1 (latest)
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
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.
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
Good to see that there is a workaround for this - I queried this very early on in PowerQuest
@fast jungle has there been updates to this at all? just curious
Nope
Next step if you want to poke around is seeing if/when unity will unload the data
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.
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:
- 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;
}
}
}
- 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
...
}
- 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);
}
}
}
- 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.
@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...
my second name is NonTrivial
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...
I'm not even able to start the game π
Oh yaay
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)
Have you put your atlases in resources?
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 π
If that doesn't work then separating rooms correctly won't help either afaik
ah, right
well, rooms are linked to more things than just sprites, so that was my thinking
It only takes a sec to move them
But you might not have the Atlas loading code that's in 0.16
ok, so just the atlas itself, or also the sprites?
Yeah
nope, I'm still on 0.15 or something like that
The sprites aren't built into the game, just the atlases
(unless unity is doing something really silly)
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
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
ah, right...
But I didn't look very hard
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
Yeah. One of those I think. But not sure off the top of my head
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
I just moved stuff into resources and checked which got bigger when I was experimenting π
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...
That's probably the one that's loading at startup
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
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
yep, that's what I'm trying right now, don't care if it doesn't work, but at least should load π
Do you have FMOD .bank files in the StreamingAssets folder?
nope, don't use FMOD myself, it's just whatever Unity is doing under the covers π
Ah okay, was going to say that they can get pretty large!
it takes around 10 minutes to build the game each time, fun...
it now crashes on a separate part, so I guess that did something π
@fast jungle there is https://docs.unity3d.com/ScriptReference/Resources.UnloadUnusedAssets.html and https://docs.unity3d.com/ScriptReference/Resources.UnloadAsset.html for unloading Resources, so that might help you
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
oh, that's not very useful then π
That's basically where I got up to when I stopped. Didn't look into it any more than that
right
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
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
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)
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?