While creating a game recently I noticed that I was slowly leaking memory…approximately 1 to 1.5MB per 2 minutes or so. Begin my hours long dive into my code to find the culprit. I was able to narrow it down to one line of code from profiling and multiple commented out sections of code.

testSprite.physicsBody = SKPhysicsBody.init(rectangleOf: CGSize(width: 200, height: 20))

What? How was this even possible, all I was doing was simply creating a physicsBody for a small square sprite. I created a new blank project, did the same enclosed method of…

The same memory leak was occurring. If I commented out creating the physicsBody, the memory leak never occurred. This gave me flashbacks of when I had first encountered a memory leak with SpriteKit with “view.showsPhysics = true” however I did not have this turned on this time around so I was a bit puzzled. I had to dive a bit deeper into profiling so I could get to the bottom of this. Running the allocations instrument I could mark timeframes or “Generations” to see how much memory was leaking given a period of time. Keep in mind that all I did before this was tap the screen once to create a single testSprite and never touched the screen the rest of the time during the profiling. The memory leak grows without stop - without any further input at all. From what I’ve noticed, all thats required to set this off is to create any type of physicsbody at all. Going by the time stamps below you can see that from Generation C to Generation D we grow 733KiB in around 1 minute and 20 seconds or so.

If we dive deeper into the Generation C timeframe we can see the cause of whats causing the bug.

CAMetalDrawable and _NSArrayM (Also a metal function) look to be the culprits. Diving in a bit deeper…

Diving deeper into CAMetalDrawable, we see that it’s creating a bunch of these 64 byte allocations. Diving into one of these allocations reveals…

That theres multiple things calling Retain/Release on this, but one in particular calls a Retain, but never has an accompanied Release, you can see it’s the one in the middle, Response under “Jet” — jet_context_Metal:create_texture_from_Metal_D… etc. Therefor ARC never releases these allocations and these are kept in memory.

Solution

OK — thats great, so I found out what was causing it and that it wasn’t anything that I was doing, but short of creating a new game engine in Metal it didn’t look like I was going to be able to fix this one without either ditching SpriteKit, or just accepting that my game would have a small memory leak. But alas I stumbled onto an interesting techincal QA from Apple. “How can I specify the renderer for SpriteKit and SceneKit?” The solution being ditching Metal all together for OpenGL. All though I’m sure Metal provides numerous benefits to big 3D games, my simple 2D games really do not needed the extra boost. With that said all I had to do was to add “PrefersOpenGL” with a Boolean type to = YES in my info.plist file

and BOOM! Stable memory usage. At least until the next one anyways. I’ve submitted this to the bug tracker for Apple to review, hopefully it is fixed sometime soon.