How to fix memory leaks in iOS applications? - swift

I have found few memory leaks when I am running my application. For your reference, I am sharing the screenshots of Instrument debug logs and also Xcode Debugg memory graph tool. I am not getting what is going wrong here. Please help me to resolve memory leaks.
Please help me to fix the memory shows in the image. Thank you.

I know this is an old question, but a few observations.
When you have a lot of objects that are leaking, focus on high level objects (especially your own classes). We do not care why the array was not released. We care about why the item that is keeping a strong reference to it was not released. XTubeManager and GlueTubeManager are probably good places to start searching, but I don't know what other high level objects appear in the panel on the left.
When you have leaks, it is very useful to use the “Malloc Stack Logging” feature. So edit your scheme (command+<; or “Product” » “Scheme” » “Edit”) and go to the “Diagnostics” section and temporarily turn on “Malloc Stack Logging”:
Then, when you select a leaked object, you can see where it was instantiated but using the memory inspector panel on the right:
Look for entries in that stack trace that are white (your code), as opposed to all the system items that are in gray. When you hover items in that stack trace, there is even a little arrow that lets you jump to the code in question. In my example, the leaked object was instantiated in viewDidLoad.
This will not tell you why it leaked, but you will be able to see where the object in question was instantiated in your code, and you can start your investigation from there, diagnosing why an object created at that point in your code still has lingering strong references.
Remember to turn off the “Malloc Stack Logging” feature when you are done with your diagnostics.
As an aside, when we see URLSession objects that were not released, that begs the question of whether you instantiated a URLSession object (rather than using the shared instance) and neglected to call finishTasksAndInvalidate. Ideally, you would have a single URLSession and reuse it for all network activity (or use the shared instance), but if you must instantiate sessions, make sure to invalidate them when you are done.

You do NOT need to use Instruments. That's the old way. Use Xcode itself.
See Visual Debugging with Xcode
- 24:45
Watching the video is a MUST, but the summary of the video is as such:
There are two type of memory problems. You just have to repeat a flow in your app 2-3 times to be certain the memory graph has caught it
Leaks. Xcode will annotate this with purple icon. Possible are: delegates, closures
Abandoned memory. Xcode will not annotate this. But it's still increases your memory footprint. possible examples are: A repeating timer that is never invalidated, NotificationCenter, A never ending DispatchWorkItem
For Leaks the memory graph is a loop ie two way.
For Abandoned memory the graph is NOT two way. It's just an object one that Apple categorizes as 'root path' referencing your object and never letting it go. For more on this see here

In this case, just because some tool says you’ve got a memory leak doesn’t mean you have one. The amount of data seems to be less than 1MB, that’s nothing. Your tool suspects there’s a leak because data was allocated and not released, but these are single objects. Quite possible that memory is going to be released or reused later.
Use your software for hours and check if memory usage gets larger.

Memory on mobile devices is a shared resource. Apps that manage it improperly run out of memory, crash, and suffer from drastically decreased performance.
so to fix it follow this steps
Open Xcode and build for profiling.
Launch Instruments.
Use the app, trying to reproduce as many scenarios and behaviors as possible.
Watch for leaks/memory spikes.
Hunt down the source of the memory leaks.
Fix the problem.

Related

Autorelease pool page corrupted

Whenever I am using ASIHTTPRequest for making webservice calls I am randomly getting the following crash:
autorelease pool page 0x9418000 corrupted
magic a1a1a100 4f545541 454c4552 21455341
pthread 0xb0103000
My code is ARC-fied and used -fno-objc-arc for the .m files of ASIHTTP class.
Does anybody have an idea about this or did anybody face this kind of issue before? Thanks in advance!
This likely indicates that you're stomping memory somewhere else. I'd start by turning on memory diagnostics and looking for mistakes. The most likely place to cause these kinds of mistakes is in C code, particularly when using C arrays or C strings. You're probably writing outside of your allocated memory, or writing into memory after you freed it.
There have at times been compiler bugs that would cause this kind of problem, but these are very rare, and I would strongly suspect your code first.
As Rob pointed out, this is likely an indication that you're misusing memory elsewhere. To turn on memory management diagnostics as of Xcode 8:
Click the scheme menu in Xcode and choose "Edit Scheme..." at the bottom.
In the Run step, go to the Diagnostics tab.
Under Memory Management, turn on all four options. I generally find Guard Malloc to uncover the most problems but they can all be useful.

CFString Memory Management Issue

I am developing an app for the iPhone and am encountering some memory management issues. During execution of the app the live bytes continuously increase without bound. I have tried to track down the issue within my code but cannot seem to find anything that would cause the live bytes to increase so dramatically. The one thing that I have noticed during execution is that the allocation for CFString(Immutable) increase the most rapidly and never decrease or stay constant. Does anyone have any idea why this may be happening? All that the app is doing during this execution is populating a table view from a local array or strings, then downloading another array of string objects and populating a different table view. I am using ARC.
Given the lack of anything concrete to go on, I'll give you somewhat general counsel:
See Finding leaks with Instruments for guidance on how to use Instruments to find leaks.
For specific advice how to go from you allocations, to a more meaningful analysis of the source of those allocations, see point #4 of this Stack Overflow answer. In short, highlight one of your unexplained jumps in allocations, set the bottom window to show you the call tree, hide system libraries, and see in which of your routines the memory is being consumed.
Also, don't overlook the static analyzer, which is especially important if you don't use ARC, or if you use any Core Foundation calls.
Are you doing anything with Core Foundation functions? If so, you obviously need to know that you either have to explicitly transfer ownership to ARC (with either CFBridgingRelease or __bridge_transfer) or manually call CFRelease. The static analyzer of my prior point would point this out to you, though.

EXC_BAD_ACCESS after convert to ARC but can profile properly with no Zombies

It's a weird situation for me that I cannot run my project on device or emulator but when I choose profile instead of run option, the app run flawlessly without any zombie guys.
It happens after I convert my project to ARC. I just modify code as Xcode tell me todo and due to the size of this project, I cannot look through every line of code.
ps. I'm the third hand on this application, so it's almost impossible for me to understand 10k lines of code.
Have you tried enabling Zombies in Xcode itself without profiling? This will set objects to never dealloc so that when you message an object that has a zero retain count, it will know what the object is and tell you. Just make sure you turn it on again so that objects will dealloc as normal.
See how to do that here:
How to enable NSZombie in Xcode?
the following can help you after the fact, but it's best IMO to perform them before migration; if a problem exists, ARC will solve some issues while abstracting others from you:
1) Create more Autorelease Pools one approach which might help you narrow things down is to explicitly create autorelease pools -- this can help localize some of your app's memory related issues. explicitly adding autorelease pools has other benefits, so this can be done not only for bug-seeking.
2) Use GuardMalloc as well, there are other memory related tools -- your app should also run fine with GuardMalloc enabled. switching to ARC could change the point of destruction -- you may be holding on to a dangling pointer.
3) Remove all Leaks finally, this may sound backwards -- remove all leaks possible. you want memory operations and lifetimes well defined. if you have an occasional leak, your issue could be hard to detect. oftentimes, reducing leaks can help you isolate the problem by making the problem easier to reproduce.

Will Apple reject my iPhone application because of increasing memory usage?

I have an application with multiple views. It works pretty fine without any leaks or crashes. But when you run using performance tool for leaks, I see when I switch through multiple views and comeback to home screen, my overall size of the application gets increased. Like if its 1.53MB after visiting 4-5 different views and getting back to screen increases the consumption to 1.58MB or less but definitely greater than 1.53MB.
I tried resolving this issue but not able to figure out where I am going wrong since there are no memory leaks.
Does anyone know what could be the problem?
Will apple reject my application on this basis?
I would go back and forth between the screens many many many many times (at least one hundred times). If the memory continues to grow (linearly) during that time, you have a problem. If the memory stabilizes, you might be okay.
Definitely keep trying to fix you memory leaks. But if it's small, I doubt Apple will notice it. I mean, their own apps leak some too. You could get rejected for it, sure. But realistically, leaking a few bytes here and there shouldn't prevent an approval by itself.
(Source, 2 apps approved, one with the same issue, a tiny little memory leak I couldn't track down. I submitted it and was approved. Shortly after, I found and fixed it and released it as part of an update).
If an application has an increasing memory footprint on a known stable state for example named A after going into and coming back from state B which should have no persistent affect on state A and there is no memory leaks this problem called (as much as I know) the lingering memory.
Checklist to be sure if you have lingering memory problem:
App has no memory leaks, or no memory leaks on non-system code when profiled by Instruments.
State A and State B are individually stable states, like in state-machine.
State B has no permanent affect on State A, or it's memory. State A could be a gateway, a menu to another states like State B or State C. But Child states has no or limited info about state A and makes no change about State A.
On loop state changes starts and ends with root state for example A->B->A, A->C->A, A->B->C->A; you encounter increasing memory usage on State A. Memory usage on other child states are not important.
To spot and solve this problem profile your app with instruments. But instead of monitoring leaks, you should monitor allocations and total memory. Every time your app gets to State A, including start, take a memory snapshot. (There is a button for that :D) After snapshot go to State B, State C and use your application as it suppose to. After coming back to root state, in this example State A, take another snapshot. Instruments will show you memory allocations and difference delta in total memory between snapshots. It will also give information about for which object the memory had allocated and when if possible. If it was your code you probably will see the type of class and allocation point. Instruments can not help you about when the object should have been released but when you got the lingering object or memory, figuring out the deallocation point should be much easier.
BUT! Do not forget:
OS and Framework codes could have leaks and lingering memory problems like every OS. If you are sure that it is not your code leaking or lingering in the memory the everything is fine. That was the case in my app and it got approved(App: Tusudoku). System function often use additional memory if there is available, but they immediately release it when received memory warning. Although devices has limited memory, it is a waste if still not used, and using memory does not make memory chip to use measurably increased electrical current. Using memory to the limits for performance and immediately releasing it when someone definitely needs it, is best possible practice. These cache memories does not tend to be grove over time linearly but you should force memory warning every time app gets to root state, in this example State A. So this way you will be sure any cache memory allocated by system or frameworks will be deallocated, then you take the snapshot.
Most of the apps on the App Store® has memory leaks and other memory problems. The question is how this affect user. Non-linear lingering memory with rapidly dropping acceleration on increase velocity generally won't be a reason for rejection. Calculated the memory usage as 15MB for a perfect working app but if it worked, no problem, say that it will reach 20MB limit max ever and you are good to go. So you later fix your memory problems. Bu if your application has a linear or worse increasing memory usage and can not release that memories when needed, that will be a critical problem.
For more information about memory usage please consider reading official documentation and watching WWDC videos(That's where I learned all about memory fixes using Instruments).
There is no set in stone answer.
On the one hand is the fact that your application may have an obscure memory leak would be enough to reject it according to the posted policies.
On the other hand documents submitted to the FCC by Apple (in the AT&T+Apple vs. Google monopoly fight) give enough detail to work out just how much goes into reviewing an app - unless Apple lied the average app is reviewed by 2 people, and each of them spends around 5 minutes and 38 seconds (assuming Apple doesn't give breaks) to determine if your app passes or fails.
So the answer largely depends on if this memory leak can be discovered in the first 5 minutes of examination by some of the most overworked testers in the industry.
If you are using UIImageViews in your views, then part of the extra memory could be the caching that it does. See here.
Sometimes when we load views, and then switch to another, we leave the view around. For example, if you have a rootviewcontroller that has all the views as retained properties. Normally when you remove a subview, it is released, but not if you have it retained in your viewcontoller. As yu can see, that would add up to memory consumed, but not freed. It's not a leak, except that it gets released only when you release or remove the rootviewcontroller.
You could try to go through and find places where memory is tied up like this, or you could justify it based on the added speed of going through views without having to wait for them to reload.
In summary, it is good to know why your views and other objects consume and hold on to memory, but you may find that all those uses are justified, and you want to keep things that way. Having said that, I don't think Apple will be rejecting our app for decisions like this. If your app crashes because of memory usage, then that would get it rejected.
You're describing very typical memory usage.
If your app runs out of memory and crashes while they're testing it, they will reject it. Beyond that, you're fine.

In CocoaTouch (iPhone OS) how do I find/eliminate leaks that the Instruments Leak tool doesn't find?

I have an iPhone app that is running great in the simulator. It responds well to the memory warnings by getting rid of everything that is not absolutely essential. When I run it on the device, it runs well. But after a certain amount of usage it crashes with error code 101 - which, from what I can tell, is the OS killing it due to memory usage. I can see the memory warning (I'm logging it), and my app responds to it, but dies shortly thereafter.
If I look at the app in Instruments (either on the device or in sim), it doesn't find any leaks. In addition, the net memory usage is in the range of 600-700k bytes. Transitioning from the different views of my app increases memory usage (as expected), but when the views and controllers are released and dealloc'd, the memory usage never quite goes as low as it was. However, the addition is usually only something in the range of 1000-2000 bytes. So while Leaks shows me no leaks, I suspect there is an issue somewhere. I've also looked at all of the objects I'm allocating, and all of them seem to be reclaimed as expected. The only objects I see that keep increasing are GeneralBlock-N (where N is some number)
Should I not pay any attention to Instruments net usage figure? What would be the next steps in trying to diagnose the issue?
ADDED: I'm not making any calls to malloc() or any CoreFoundation libraries that would return a buffer that I'm responsible for. The only non-Obj-C calls I'm making are logging statements to NSLog.
One quick thing to try is running the Clang static analyzer. This will find some, but not all, issues in your code that you might be missing. It checks the code at compile time, so it's by no means infallible, but will almost certainly find most glaring problems.
You should also run your application with the memory monitor instruments to see overall system usage on the device.
Leaks only finds memory that is not referenced by anything, but still retained.
What you are seeing is that you have left memory retained, and still referenced by something.
One thing to look for especially, is that if you have passed a reference of a class to something else as a delegate that you free it in your dealloc method.
Similarly, if you have subscribed to any notifications you should unsubscribe in viewWillDisappear: (if you use the general unsubscription method in a view controller do not forget to re-subscribe to the memory warning notification.
Timers are the same way, deactivate them when a view goes away and re-enable them when the view comes back (unless of course you need a timer running the whole time your application is running).
Basically be suspicious of anything you give a reference of a class to, and try to figure out how you might eliminate that link whenever possible (either in dealloc or viewWillDisappear: or both).
Here's a summary of what I've learned (thanks to some excellent answers and comments):
Object Allocation is NOT the same as Memory usage. The answer to my question about ObjectAlloc's net bytes element is that you shouldn't be paying attention to it - at least not when determining issues with the amount of memory you are using or whats causing it to crash. It doesn't reflect the true memory usage of your application.
My amatuerish guess is that ObjectAlloc only shows you the memory taken up by the direct object itself. So if you have an UIImageView, it takes up just a handful of bytes to store the various properties, but it might be pointing to an image in memory taking up a bunch of space. Therefore, looking at ObjectAlloc is helpful only in making sure you're not creating and keeping objects around, it won't give you an idea of how much memory you're using or how much you can use before crashing.
MemoryMonitor will give you the total memory usage. You can constrain it to viewing only your app's usage by using the search tool in the bottom right of the Instruments window.
Both ObjectAlloc and Memory Monitor (as well as the Leaks tool) are plugins for Instruments - just in case thats not obvious to someone else. You can launch Instruments from within XCode by doing Run -> Start with Performance Tool. Once inside of Instruments, you can open the Library and add new plugins to monitor different aspects of performance.
One thing to look for is circular references.
(I don't want this to sound patronising - just want to make sure I'm being clear:) If object a refers to object b and object b refers to object a, there may not be a reported "leak" because all the memory is still referenced - but this may be an orphaned island of objects, seperated from your app and never reclaimable. Of course it may involve more objects ( a refers to b, b refers to c, c refers to a, etc).
If you're building up a graph of objects somewhere, and there are any back or cross references, be sure to break the circles if you release the root (there are different ways of doing this. The simplest is probably to make sure each class in question has a releaseAll method, or similar - which calls releaseAll on it's child objects, then releases the child objects - but this isn't always the best solution).