How can identify strong reference cycles in Swift? - swift

Is there a tool or method to locate strong references cycles in my SWIFT code?
A strong reference cycle is when two instances of classes reference each other without the proper safeties (weak/unowned) hence preventing the garbage collector from disposing of them once all the variables I created stopped referencing those objects.

The method for finding strong reference cycles is the same in Swift as in Objective-C.
You'd run the app from Xcode, exercise the app sufficiently to manifest the cycle, and then tap on the "debug memory graph" button (). You can then select an unreleased object in the panel on the left, and it will show you the memory graph, often which can clearly illustrate the strong reference cycles:
Sometimes the memory cycles are not as obvious as that, but you can at least see what object is keeping a strong reference to the object in question. If necessary, you can then track backward and identify what's keeping a strong reference to that, and so on.
Sometimes knowing what sort of object is keeping the strong reference is insufficient, and you really want to know where in your code that strong reference was established. The "malloc stack" option, as shown in https://stackoverflow.com/a/30993476/1271826, can be used to identify what the call stack was when this strong reference was established (often letting you identify the precise line of code where these strong references were established). For more information, see WWDC 2016 video Visual Debugging with Xcode.
You can also use Instruments to identify leaked object. Just run the app through Instruments with the Allocations tool, repeatedly (not just once or twice) returning the app back to some steady-state condition, and if memory continues to go up, then you likely have a strong reference cycle. You can use the Allocations tool to identify what type of objects are not being released, use "record reference count" feature to determine precisely where these strong references were established, etc.
See WWDC 2013 video Fixing Memory Issues and WWDC 2012 video iOS App Performance: Memory for introductions to identifying and resolving memory issues. The basic techniques proposed there are still applicable today (though the UI of Instruments tools has changed a bit ... if you want an introduction to the slightly changed UI, see WWDC 2014 video Improving Your App with Instruments).
As an aside, "garbage collection" refers to a very different memory system and isn't applicable here.

You can add deinit functions to your classes that will get called when your objects are deallocated.
If deinit isn't getting called, while your app is running, you can press the Debug Memory Graph button (circled below) and inspect what has a reference to what.
Use the dropdown menus at the top of the middle pane to toggle between classes and instances of classes.
If something is getting allocated over and over again without getting released you should see multiple instances, and you should be able to see via the directional graph if one of its children is holding a strong reference to its parent.

Use instruments to check for leaks and memory loss. Use Mark Generation (Heapshot) in the Allocations instrument on Instruments.
For HowTo use Heapshot to find memory creap, see: bbum blog
Basically the method is to run Instruments allocate tool, take a heapshot, run an iteration of your code and take another heapshot repeating 3 or 4 times. This will indicate memory that is allocated and not released during the iterations.
To figure out the results disclose to see the individual allocations.
If you need to see where retains, releases and autoreleases occur for an object use instruments:
Run in instruments, in Allocations set "Record reference counts" on (For Xcode 5 and lower you have to stop recording to set the option). Cause the app to run, stop recording, drill down and you will be able to see where all retains, releases and autoreleases occurred.

very simple approach is to put a print in deinitialiser
deinit {
print("<yourviewcontroller> destroyed.")
}
ensure that you are seeing this line getting printed on the console. put deinit in all your viewcontrollers. in case if you were not able to see for particular viewcontroller, means that their is a reference cycle.possible causes are delegate being strong, closures capturing the self,timers not invaidated,etc.

You can use Instruments to do that. As the last paragraph of this article states:
Once Instruments opens, you should start your application and do some interactions, specially in the areas or view controllers you want to test. Any detected leak will appear as a red line in the “Leaks” section. The assistant view includes an area where Instruments will show you the stack trace involved in the leak, giving you insights of where the problem could be and even allowing you to navigate directly to the offending code.

Related

Memory Leak in iOS application - ARC

I have a hard time figuring out, where my app is leaking. I have tested it with the "Instruments" profiling application by allocations, with heapshots. This is what I got:
As you can see, the allocations is increasing. It increases every time I transitions between two views, with an fade effect. In which of the following heapshots should I look in, in order to find the leak and what kind of objects should I look after, when I go through the heapshot/heapshots?
Thank you for the help in advance :).
ARC can only deallocate the memory if you are not holding any references to it anymore. Since the leaks instrument doesn't indicate any "real" leaks (in the sense of memory that you don't have access to anymore), you are probably seeing a case of abandoned memory. You are still holding references to objects which you don't need anymore, so they don't get deallocated.
It doesn't really matter which snapshot you inspect after the baseline. The list of objects in a snapshot can be somewhat overwhelming though... but often it helps to filter it down to your own classes. You can do this by typing your class prefix into the search field in the upper right. If none of your classes show up in the snapshot, you can at least look for classes which you directly use.
Also make sure to enable the "Record reference counts" option in the inspector pane of the allocations instrument. When you have this enabled you can click on the little right-arrow next to the objects listed in a snapshot (not the class name, but the object represented by its memory address) and see a complete history of this object. This makes it easier to see who is holding references to it.
Hope this helps!
Build your code with the 'Analyze' option; track down and eliminate every issue.

What does <non-object> in Allocation "heapshots" mean?

I'm having a hard time fixing memory related issues in my iPad application, but, good thing is, that I've learned about "heapshots" because of that. Bad thing is, I'm still unable to figure out what some of the information provided to me means.
So, what are these non-objects which are still alive and takes most of the memory described in Heap Growth? Is it possible to get rid of them? It looks like that most of them are related to various drawing operations, CALayer, context and etc (Category:"Malloc" or "Realloc"). I can provide more details if needed.
It means that memory block was allocated not for an object (e.g. pure c structure).
Usually they are allocated by system framework code, so there are some other objects that leaks. E.g. if you forgot to release UIView, then it's layer will not be freed too.
You can open "Extended detail" panel (see "View" menu) and analyze the call stack. Take in mind that one release you forgot can lead to a lot of memory leaks, so try to fix the easiest leaks and then check whether other leaks disappears.
One more trick. You can disable functional block of your application one by one and see whether leaks disappears. So you will be able to locate module (class, functional block, etc) where it occurs.

Tips for finding and debugging abandoned memory and heap growth

I recently watched one of the WWDC 2010 videos: Session 311 - Advanced Memory Analysis with Instruments. The link is here.
There is an interesting example in the video on finding Abandoned Memory. They say that it is often more important to debug than leaks but can be more difficult.
Abandoned Memory is defined as "Accessible allocated memory that is never used again".
A leak is defined as "Allocated memory that can no longer be reached."
The primary way to find Abandoned Memory is to take heap shots using the Allocations instrument.
However, after determining that I have abandoned memory in my code, I have found that it is really difficult to find out exactly where it is coming from.
I am looking for some good tips or resources for finding Abandoned Memory.
Thanks!
In Instruments, you can get a call stack for any object identified by a heapshot. Screenshot:
So what we've got here is a contrived case where I allocate a 1MB NSMutableData everytime the user taps a button. In the center-bottom pane, I've got 4 heapshots, and I have one expanded to show the objects that were created but not released since the last heapshot. I've highlighted a 1.25MB "non-object" allocation, and in the right pane, it shows me the exact call stack where this allocation occurred. One trick about that panel on the right is the slider along the bottom -- it controls the elimination of stack frames. If you want to see all the stack frames, drag it all the way to the right. Grayed out frames are those for which you don't have source code, and non-grayed-out frames are your code (or code you have both symbols and source for.) (Also, if you're not seeing the panel on the right, check the "View" buttons in the toolbar.) What other information are you looking for?
To summarize bbum's excellent blog post:
Profile your app using Instruments
Use the Allocations template
When the app isn't running, click the little i next to the Allocations track header and check Record reference counts; this will let you know where the items are being retained, not just where they are allocated.
Run your app, do something, then return to a default state. For example, open a new document window, then close it.
Click the "Mark Heap" button in Instruments.
Repeat steps 4 and 5 several times.
When you review the allocations in Instruments, you can click the right-arrow button to see a history of events for that instance, including all places it was allocated, retained, released, and autoreleased.

No memory leaks, yet still running out of memory?

In my cocos2d application I have run through it using instruments and removed all memory leaks. I have my game outputting how much memory is in use on the screen and it is constantly rising as the game progresses until I eventually run out of memory. The amount of objects on screen doesn't increase by very much each level. Its a fairly simple game so i should not be running out of memory so soon.
I am removing all objects from a level when it ends and reallocating new ones when a new level begins. Instruments tells me there are no memory leaks. When i run through instruments to show me where the allocations are the bulk of the problem doesn't seem to come from one place its all of my objects.
Any ideas what the issue might be?
Just because instruments doesn't show leaks, doesn't mean you're not still allocating memory you're not using. Pay attention to the ObjectAlloc graph and see if that is constantly rising without falling off.
If you allocate memory that you aren't using and can't clean up, that's just as bad as a leak, even though you haven't technically leaked anything because you've stashed some unused reference somewhere.
Look at how much memory you actually need to use or to keep for future use at any point in your app, then treat anything else previously allocated as a leak and fix it.
In Objective-C when using autorelease objects be wary of circular dependencies!
If you create object A and then an instance of object B and pass A to it, so that B retains A, and A also retains B (for example by adding it as child to A) you can easily setup a circular dependency and thus both objects won't be released.
Tip: add a -(void) dealloc method to all your scene classes, and set a breakpoint there. If you change a scene and its dealloc method isn't called after the scene transition has finished, you're leaking this scene (it's not released).
Try to find that leak by looking for a setup that's similar to the one I described above.
Be careful about autoreleased objects, since they are not released immediately. If you have sections with lots of allocations and autoreleasing, try using specific autorelease pools on them.
It happened to me when creating huge decision trees (using NSArrays) for a game AI.
A great way to check for objects that are aggregating in memory is to use Instruments' new (in Xcode 3.2.3) Heap Shot functionality.
Use the normal Allocations instrument against your running application. Perform a series of repetitive events that should come back to some known state (for example, go one level down in a navigation controller and come back). Every time you do this, click on the Mark Heap button in the left sidebar for the Allocations instrument (under the section heading Heapshot Analysis).
What this will do is mark the heap at each of the starting points for this repetitive action and compare the objects that have been created by that point with the objects that had been created by the time you marked the heap last. Only objects that have been created between those two points and are still alive in memory will be listed.
If you are accumulating objects, but they are either not leaks or are being missed by the Leaks tool, they should show up here. I've found a number of subtle memory buildups this way, particularly when you pair this with the UI Automation instrument to automate the repetitive actions you're testing.
The bulk of the problem seem to be that Sprites don't get released in cocos2d unless all actions have been stopped on those sprites. This is done using stopAllActions. Cheers for all the suggestions.

Memory crashes in iOS with real memory usage only at 5megs

I have been hunting down memory leaks for some time in my app. As of right now, as I flip back and forth between two views while watching the memory monitor instrument, the real memory fluctuates between 5 and 6 megs. This is all fine -- as far as I can tell everything is getting released properly when I pop back off a view. However, the virtual memory continues to increase and my available real memory drops rapidly every time I push the view back onto the view stack (even though the real memory usage of the app isn't increasing). Eventually, this all leads to an out of memory crash. Is this a telltale sign of any specific issue, or am I just missing a memory leak somewhere?
EDIT: The odd part is, I get an out of memory crash while the app is still only using up about 5 megs of real memory.
Do not use -retainCount.
The absolute retain count of an object is meaningless. It is an implementation detail. It may be influenced by many factors well beyond your code.
You should call release exactly same number of times that you caused the object to be retained. No less (unless you like leaks) and, certainly, no more (unless you like crashes).
See the Memory Management Guidelines for full details.
In this specific case, you are leaking memory but in a way that leaks can't find it. The objects that are leaked are still connected to your overall application's object graph somehow. Maybe through a notification, maybe through delegation, doesn't matter -- leaks sees the reference and concludes that the object might still be live.
Use the Allocations Instrument. Configure it to only track live allocations (since you don't care about objects that have been deallocated). Do some stuff with your app. Check out what Allocations knows about and explain why all those objects should stick around. You can use the data mining facilities to filter down to just your objects.
Anyway, you can also use the "Build -> Build and analyze" option to find suspicious non-conventional code.
Another reason why you may have memory lost in lower API layers is if you don't remove all your views from your view hierarchy (aka : not calling [view removeFromSuperview] everywhere). At least that's what seemed to have happened to me.
Note that most of time this isn't required, as you would simply release the main view and all its subviews, then rebuild it from the view controller when needed. Things start to get more tricky when you're not releasing the whole hierarchy but instead simply remove some of them from the hierarchy.
In that case, I came to the conclusion that you may have buffers or layers still cached in lower API parts, and in that case your Allocation instrument won't help you.
In order to monitor correctly you'll need to use the "Memory Monitor" (in System). You'll see that the "Physical Memory Free" line dropping close to 0 is the most reliable indicator that a Memory Warning will be issued.
Another advantage of using this instrument, is that you can attach it to a running process, thus making it possible to have console output and instrument running together easily.
Circular references also won't be counted in Leaks but you can track those in Allocations. Best bet is to fire up Allocations and get to a state where you think everything should be gone (or certain objects should be). If they're hanging around go dive in to them and look at where they've been retained and sort out the proper memory ownership/releasing.
As for Allocations, there are some things that it doesn't track that can affect the overall memory. Some of the things include some CGImage backing stores, some CoreAnimation stuff and some database stuff.
Have you used the "Leaks" Performance Tool? And check out the logs in Organizer to see if there's anything there.
Also look into the dealloc for the view controllers and make sure you are properly releasing all of it's objects?