how to fix memory leaks with xcode (Swift 3) - swift

i've made a game in Swift and it has a single and a multiplayer modes, and it seems that i have a problem with the memory management, because the app occupies 150 MB and i have no idea why.
the memory debugger of xcode shows that there are 15 issues when i choose a multiplayer game, but in the single player mode it semmes that there are no leaks and still it got 150 MB usage.
here are a screenshot of the debugger in action and i'll appreciate any help with all these triangles, circles and rombs.
thanks in advance!

This looks like a strong reference cycle.
Usually this happens when you don't declare objects that you use in closures as weak. In order to understand what a strong reference cycle is, check the following resources out:
Blog post about strong reference cycles
WWDC videos available (e.g. here and here)
Although the WWDC videos are a little bit older, the main idea is still the same. At least two objects are (transitively) holding a strong reference to each other. When both get released (e.g. when a GameScene is deallocated) they still point to one another, so the system is unable to deallocate them.
Usually, you get a strong reference cycles in the context of closures:
myMethod(...) { (param1, param2) in
self.myVariable = ...
}
If you have a structure like this in your code, try to make self weak. i.e.
myMethod(...) { [unowned self] (param1, param2) in
self.myVariable = ...
}
Since I don't see the code, I can't exactly see where the problem is but it seems that you have a strong reference cycle in your dictionaries. Then it might not be a closure problem.

Related

Do functions given to the escaping closures create strong reference to the functions owner instance

I have massive memory leaks in the project I am currently working on. The VC's never disappear from the memory and unfortunately that causes many, many problems right now. The only culprit that I can think of is the way I use closures in the name of readability and simplicity since none of those closures captures self strongly inside. The way I use is as following:
functionWithEscapingClosure(closure: functionGivenToTheClosure(_:))
If this creates a strong reference I have soo many refactoring to do, if not I will look elsewhere. Thanks in advance!
I have looked for an explanation to the subject online, searched through the Swift documentation but couldn't find any information.
Your snippet there is essentially equivalent to:
functionWithEscapingClosure(closure: { parameter in
self.functionGivenToTheClosure(parameter)
})
So yes, it would implicitly capture a strong reference to the instance that owns the function passed in.
You would need to explicitly do the weak capture to break the cycle:
functionWithEscapingClosure(closure: { [weak self] parameter in
self?.functionGivenToTheClosure(parameter)
})

Memory continuously increasing on swift application

I'm coding a generic Swift application (not for iOS, it will later run on raspbian) and i noticed a constant increase of memory. I checked for memory leaks also with the inspector, and there are none.
To dig deeper, I created a blank application for macOS, and I just wrote those lines of code, which are only for testing:
var array = [Decimal]()
while(true) {
array = [Decimal]()
for i in 0..<10000
{
array.append(Decimal(string: i.description)!)
}
sleep(1)
}
As I know, at beginning of every cycle of the while loop the entire array that was filled in the previous cycle should be deleted from memory. But seems that this is not happening, with those lines of code the process memory rises indefinitely.
I also tried the same code on an iOS project putting it on the application function (the one that is called at the beginning in the app delegate) and I noticed that in this case, the memory remains constant and do not rises up.
Am I missing something on the non iOS project?
The Decimal(string:) is creating autorelease objects. Use an autoreleasepool to drain the pool periodically:
var array = [Decimal]()
while true {
autoreleasepool {
for i in 0..<10_000 {
array.append(Decimal(string: i.description)!)
}
sleep(1)
array = []
}
}
Normally the autorelease pool is drained when you yield back to the runloop. But in this case, this while loop never yields back to the OS, and therefore the pool is not getting drained. The use of your own autoreleasepool, like above, solves that problem.
FWIW, Apple has been slowly excising the use of autorelease objects in the Foundation/Cocoa classes. (We used to experience this problem with far more Foundation objects/APIs than we do now.) Clearly Decimal(string:) still is creating autorelease objects behind the scenes. In most practical cases, this isn't a problem, but in your example, you will need to introduce your own autoreleasepool to mitigate this behavior in this while loop.

Assets singletons and reference cycles

I currently have an Assets singleton class that provides me access to textures, sounds, and music. As my partner and I are going through the memory management stage of our project we have realized that we may have a serious leak being created, and based on my use of Xcode instruments our biggest issue may center around this singleton class. While there are certainly other leaks present, we have noticed that when moving between map screen and game screen back and forth, there is a fairly steady increase of ~100 mb, which appears to correspond to our 11 map assets. With that context, my question is this:
Would the code below create a retain cycle, and if so, can it be managed with the existence of the singleton class, or ought we break this thing up s.t. texture atlases are held separately?
func transitionToMapScreen()
{
//I hope this isn't necessary eventually, but we were trying to ensure all game textures and emitters were deallocated
Assets.sharedInstance.deallocateGameAssets()
gameScene = GameScene()
Assets.sharedInstance.preloadMap
{
[unowned self] in
let mapScene = MapScreen(fileNamed: "MapScreen")!
mapScene.preCreate()
mapScene.scaleMode = self.scaleMode
// Transition with a fade animation
let reveal = SKTransition.fade(withDuration: 2.0)
let fadeMusic = SKAction.run
{
Assets.sharedInstance.bgmTitlePlayer?.setVolume(1.0, fadeDuration: 1.0)
Assets.sharedInstance.bgmTitlePlayer?.play()
Assets.sharedInstance.bgmGamePlayer?.setVolume(0.0, fadeDuration: 1.0)
}
let stopGameMusic = SKAction.run
{
Assets.sharedInstance.bgmGamePlayer?.stop()
}
let transitionAction = SKAction.run
{
self.view?.presentScene(mapScene, transition: reveal)
}
self.run(SKAction.sequence([SKAction.wait(forDuration: 1.0), fadeMusic, SKAction.group([stopGameMusic, transitionAction])]))
} // end Assets.sharedInstance.preloadMap completion block*/
}
From what I understand about retain cycles in Swift, isn't this creating a self reference to the Assets class and creating a memory leak? And could this explain the behavior of our map assets being retained in memory? And if so, what is the proper method of managing this?
I wanted to post this here for those who might be looking for an answer to a similar problem related to hunting down retain cycles to explain memory growth issues. First, thanks very much to all those who helped me halt my neurons' random frantic attempts to find retain cycles where there were none (or were not ones big enough to matter). Now:
First, retain cycles are scary, sure, but using instruments to find them and then managing as Apple recommends since Swift 4.2 is appropriate:
something()
{
[weak self] in
guard let self = self else { return }
self.whatever()
}
I've seen some people argue that you should determine whether unowned or weak makes sense -- this honestly takes the guesswork out and is much easier. I did find unowned crashes are rare anyway at least for us, but I won't opine on your app, and this solves things. Now, then, once you have cleaned house:
We discovered that our memory growth issues stemmed not from our asset singleton class inherently but rather the sheer size of our texture atlases and corresponding overlapping usage of those atlases. I cannot recommend this discussion enough: How does SKTexture caching and reuse work in SpriteKit?. That will explain conceptually the issues you might face with atlases better than I can.
Summarily, however: SpriteKit manages the allocation of your texture atlases, and accordingly you must understand that if you have a very large atlas that is frequently loaded it may not manage it as you expect (I still don't have enough detail to describe that in a better way, but as I said please reference the discussion above as well as Apple's developer guide on SKTextureAtlas: https://developer.apple.com/documentation/spritekit/sktextureatlas).
Now, related to that Apple discussion, I noted this line, which I think really ought to be bolded and in red: "SpriteKit implicitly loads an atlas when one of the atlas's textures is accessed." This was critical to solving what I think was our underlying issue: we had a few places where we accessed textures in the atlas via a single instance for some reason -- you must recognize that in the case of a large atlas SpriteKit will then load your entire massive atlas into memory. So I no longer take lightly Apple's note to manage your atlas sizes. Atlases are meant for assets that are always used together and are going to be drawn together. Loading disparate assets into an atlas was our mistake. We are reorganizing how we manage these accordingly.

Memory problems when switching between scenes SpriteKit

Ok so awhile back in testing I had a random crash with no error, and I have no clue why. So i went into analyze things and I came up with the following data.
As it would appear my memory usage is getting higher and higher and higher until it sorta plateus. Notice how at the beginning the slope of the general curvature is greater then later on. (as you might notice this is my first time going in and analyzing this sort of thing).
Now what happens in the game is that basically their are two screens.
1. Menu: this screen has quite a few textures but does nothing except has button to play game
2. Game: this has TOOONS of textures and has the bulk of the cpu usage because its the actual game.
3. Death: This screen has one asset, and it is a button that allows you to replay the game. This should not be using much memory OR cpu. However it still has memory. To me this screams whatever a "memory leak" is, is going on.
If you will look at the chart basically what was going on in the game was the menu started, and the first spike was loading up the actual game, then I died. Then from then on I was switching between the Game and Death screens, each spike signals the Game scene being loaded.
If this data were the way I would predict it you would se an oscillation between a very small memory use for the death screen, and then a return to a game memory usage.
Moral of the story is I am pretty sure that sprite kit isn't properly cleaning up after switching scenes and I need to know why if possible.
Btw in order to switch scenes I am using the method made by maxkargin detailed
here
BTW I am working in swift with sprite kit and SKScenes, and SKSpriteNodes
Thanks much!
There is a few reasons why this is, I had a similar problem with my games. If you do it correctly there is no need to remove stuff such as textures. Removing textures on every scene changes is also not ideal, you want to keep them in memory for performance so they do not have to be reloaded each time.
Here is a basic checklist you can use to see if you create a memory leak.
1) Add the deinit method with a print statement to each scene/class. If deinit gets called your scene deallocated correctly.
deinit {
print("Deinit GameScene")
}
2) Are you creating strong reference cycles somewhere by creating references between 2 classes?
The classic Apple example of a strong reference cycle
class Person {
var dog: Dog?
}
class Dog {
var person: Person?
}
To fix it you would have to make 1 of those 2 properties weak
class Person {
var dog: Dog?
}
class Dog {
weak var person: Person?
}
Also good practice with optionals is to set them to nil when they are no longer needed.
person = nil
Maybe check google and the Apple Swift documentation on how to deal with this. I also asked a similar question a while back
Swift SpriteKit ARC for dummies
3) Are you using closures? They can cause memory leaks.
A more common scenario in SpriteKit is these 2 examples which could/will cause a memory leak and makes your scene to not deallocate. (action 2 is a closure which captures self)
// Example 1
let action1 = SKAction.wait(forDuration: 1)
let action2 = SKAction.run(someMethod)
let sequence = SKAction.sequence([action1, action2])
run(SKAction.repeatForever(sequence))
// Example 2
let action1 = SKAction.wait(forDuration: 1)
let action2 = SKAction.run {
self.someMethod()
}
let sequence = SKAction.sequence([action1, action2])
run(SKAction.repeatForever(sequence))
A good rule of thumb is that when the compiler forces you to use self than you most likely will create a memory leak without using weak/unowned.
So to fix the above 2 SKAction examples you could either make sure you always remove all actions when you change scenes or IMO even better would be to change your code to this to avoid creating a memory leak in the first place.
let action1 = SKAction.wait(forDuration: 1)
let action2 = SKAction.run { [weak self] in
self?.someClassMethod()
}
let sequence = SKAction.sequence([action1, action2])
run(SKAction.repeatForever(sequence))
Note in all those above example you could also write
.... { [unowned self] in
and than you would not need to use the ? in the closure
self.someMethod()
When you use unowned you basically say self will never be nil which could cause a crash if it is actually nil when the closure is called. If you use weak self you tell the compiler self might become nil before the closure is called therefore self is an optional to avoid the crash.
I think it is almost always better to use "weak" instead of "unowned" to avoid this. In one of my games I was using unowned self in a closure that was called when it fetched StoreKit products from iTunes. This caused me subtile crashes because I could exit the SKScene before the closure was called. If you use weak self you will not crash because you use optionals.
Hope this helps a bit
sprite kit uses cache to retain perforemce between scenes that why switching between scenes spike up memory and this memory does not release at any case either you remove all children from scene or [self.view presentScene:nil]; their are better solution for this...
read this article carefully
https://developer.apple.com/library/ios/qa/qa1889/_index.html
manage scene with view's and remove SKView's from those view's to maintain memory in multi screen game
So based on what everyone said this is what I did. Before changing to a new scene I run functions that basically takes all textures, and sprite nodes and sets them to an empty constructor so that they are smaller, then I remove all actions, and children. This has seemed to do the trick! Their might still be other memory problems, however I need to look more carefully and tweak some things before I can be sure.
Thanks for the advice everyone!
As a side-dish answer, I had a complex scene with a lot of custom sprite kit subclasses and actions interacting together, and the only thing that prevented my SKScene subclass from calling its deinit was one delegate I forgot to define as weak or unowned, which created a classic strong reference cycle problem. So if you assigned any delegates to self in your scene's setup like this:
myCustomNode.delegate = self
Then check the definition of the delegate, it should look like this:
weak var delegate:MyCustomProtocol?
or this:
unowned var delegate:MyCustomProtocol?
If you do not have access to myCustomNode's source code, then try assigning the delegate to nil in your scene like this:
override function willMove(from view:SKView) {
myCustomNode.delegate = self
}
Also, if you get the error
weak / unowned may only be applied to class and class-bound protocol types
This is because your custom protocol must include : class like this:
protocol MyCustomProtocol : class {/*protocol definition here*/}

Finding who has a retain count to an object

I have a UIViewController which has a retainCount of 3 the moment I instantiate it. That stirs me as terribly incorrect. What's the best way of figuring out who bumped up the retainCount to 3? I'd imagine instantiating the object should give the pointer 1, then I suppose maybe pushing it onto the UINavigationController's stack might bump it up one (not sure about that though?), but the third.. is a mystery.
Adam is right that you shouldn't be overly concerned about retain counts.
But if you ever have a legitimate need for solving such a mystery, a good technique is to subclass the affected class just so you can add overrides to the memory-management methods.
E.g. in a subclass of UIViewController, you could implement:
- (id) retain
{
// Break here to see who is retaining me.
return [super retain];
}
Don't ever rely on retain counts directly. What's happened is that during the initialization process, some piece of code has retained and autoreleased the object. Because you can't tell how many times an object has been autoreleased, you don't actually know what the real retain count is.
Retain counts should only be used as a debugging aid, never as program control flow.
As long as you follow all of the rules laid out in the Memory Management Programming Guide for Cocoa, you won't have problems.
What's the best way of figuring out who bumped up the retainCount to 3?
That's approaching the problem from the wrong angle. This will confuse you and will lead you astray (and probably right past) the actual problem, when indeed there is one.
Better to think about who owns the object. Do you intend to keep the object around as the value of one of your own properties? If so, then you are one of its owners. If not, then you aren't. If you pass the object to another object to store in one of its properties, then that other object is also an owner.
These ownerships are just relationships, so it's really easy to keep them straight in your head.
“This is one of my controllers. It owns the root objects of my model and one or more view[ controller]s.”
“This is a view. It owns some parts of my model.”
“This is part of my model. It owns primitive objects only.”
“This is another part of my model. It owns some primitive objects and some other bits of model.”
If you have a solid grasp of your ownerships, then you cannot write a memory leak except by forgetting a release or autorelease message (which can happen to anyone), and you will almost certainly not write a cyclic retention (two objects retaining each other) except knowingly and with copious comments and #warnings.
If you haven't worked out your ownerships, then you have probably written one or more memory leaks or cyclic retentions that you don't know about.
Edit: And to answer the actual question, the best way to figure out what has retained—and, possibly, subsequently autoreleased—an object is to use Instruments's Allocations instrument. With it, you can look at the history of any object to see every allocation, retain, autorelease, release, and deallocation of its address.
It's not a 100% solution, but the LLVM Clang Static Analyzer can be a big help in tracking down incorrect manual memory management usage. Between the Static Analyzer and MallocDebug, you can get to be a pro at tracking down memory management issues very quickly. BTW, even though Instruments is the new hotness, I find MallocDebug far more reliable.
You can find the LLVM Clang Static Analyzer here: LLVM/Clang Static Analyzer