Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

AVAudioPlayer and SKAction.playSoundFileNamed(...) are causing a memory leak

My game is essentially finished. Checked for leaks in Xcode. Found out I was leaking about .3 MB per time the game was played. Then went to instruments and looked at persisting data.

Culprit 1:

SKTexture, was called a lot but didn't continually grow

Culprit 2:

Wish I remember the exact syntax, it was something like AudioSource, and was happening when this line was called: SKAction.playSoundFileNamed(...)

So I went to the 'Settings' page of my game and turned off the sound. Tested memory usage again and was stable. Also realized that AVAudioPlayer was leaking because the sound effects and the theme run through different mechanisms.

I tried setting the instance of AVAudioPlayer, var backgroundAudio:AVAudioPlayer! to nil upon closing, which was declared as a class variable, and that didn't help.

Is there a giant hammer I could use to clean up audio sources apparently under some strong reference cycle? I also had a problem with GameViewController when showPhysics was called. I think my issue might be the structure of the game. The main menu calls a view and scene, so you have a scene within a scene. The instances of the level scenes appear to be releasing properly, but some shadowy audio bugs are left behind. Any solutions?

like image 980
Ryan Dines Avatar asked Oct 23 '25 16:10

Ryan Dines


1 Answers

You should use SKAudioNode instances to avoid memory leaks, SKAction.playSoundFileNamed is known for this issue for a while. Do something like this (inside a SKScene):

// Initializing the SKAudioNode instance:
let soundNode = SKAudioNode(fileNamed: "mySound")
audioNode.autoplayLooped = false    

// Initializing the audio's duration SKAction:
let soundDuration : TimeInterval = 2 // For a 2 second sound!
let waitToFinish = SKAction.wait(forDuration: soundDuration)
    
// Adding the SKAudioNode instance to the SKScene:
self.addChild(audioNode)
    
// Running the actions:
audioNode.run(SKAction.sequence([.play(), waitToFinish]), completion: {
// Removes the SKAudioNode from the SKScene to free the memory:
    audioNode.removeFromParent()
})

Or you could check out my GameAudioPlayer class on Github since it does exactly what you want in this case. It handles SKAudioNodes and avoids memory leaks, and you can also load the sound resources before playing it: https://github.com/ThiagoAM/Game-Audio-Player

I hope that helps you! Good luck!

like image 164
ThiagoAM Avatar answered Oct 25 '25 06:10

ThiagoAM



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!