I have an SKScene
which is the overworld for my 2D game. It's like a neighborhood that the player can explore. The neighborhood is full of houses. Players can freely enter and exit houses. When the player enters a house, I call skView.presentScene(newHouse)
to present the interior of the house as a new scene. When the player exits the house, I call skView.presentScene(overworld)
to present the neighborhood again. The player is likely to enter & exit houses many times as they explore the neighborhood. Thus, the neighborhood scene and new instances of the house scene are presented many times.
The problem is that each time I present a house scene, there is a spike in the memory. This is expected since we are loading a new house scene. But when I exit a house scene and return to the neighborhood scene, the amount of memory use does not go down. I've tested this by entering and then exiting houses over and over. The memory use climbs by a consistent amount (~2 MB) every time I enter a house. Eventually, the amount of memory use becomes very large and the game starts dropping frames (but only in the house scenes, not in the neighborhood scene) and eventually becomes unplayable.
Why is this happening?
When working with SpriteKit I thought that best practice is to use presentScene to transition the player to a substantially different "realm" of the game world (e.g. a different level), which is what I believe I am doing here. I also thought that you are not supposed to take any action to "unload" your old scene when you load and then transition to a new scene. Indeed, the SKView documentation does not have any methods for cleaning up unneeded objects from your old scene when you present a new scene. I thought that you are supposed to trust the OS to handle the job of removing the old scene's objects from memory. That is why I simply present new scenes and don't worry about old scenes taking up memory.
I profiled the app in Instruments to check for memory leaks (Instruments is still a bit over my head at this point). I did find some memory leaks that looked very small, but no leaks that seemed to be directly causing the large and consistent memory spikes that are happening each time I present a new house scene.
Am I doing something wrong?
I believe I am taking the correct approach by presenting new scenes and letting the OS handle the job of cleaning up the old scenes. But maybe I am making a mistake in my app design that is causing this memory issue. When I present a new house scene, I pass some information from the neighborhood scene to the new house scene. This information is related to things like the appearance of the house (color, texture, contents, etc.) which is necessary because the houses are procedurally generated: each one is unique. And when I return to the neighborhood scene, I pass some information from the house scene to the neighborhood scene. But maybe the way that I am passing information between scenes is somehow unintentionally causing objects to be retained in memory. If so, what should I do to make sure that this does not happen? Is there some code I should run to clear the unwanted objects from memory when I present a new scene?
I did notice that the SKScene documentation has several methods related to presenting a scene: sceneDidLoad()
, willMove(from:)
, and didMove(to:)
. Which makes me wonder if I should be using these methods somehow to try and clear unneeded objects from memory when I transition between different scenes.
It may be that my app architecture is simply bad (it's already causing other problems for me). If so, then the solution would be to start by overhauling my app architecture to improve it. So basically, I am trying to determine if my bad app architecture is causing this memory bloat problem, or if the cause is related to SpriteKit and the way that scenes are presented.