Not sure if it's a memory leak (ARC) - ios

I'm writing custom animations and I suspect that I have a memory leak, but I'm not sure. Every time I run a given animation memory goes up a little, but it doesn't go down. To make sure, I made a test:
NSLog(#"%#", self.weakanim);
// The animation collection to run
HyAnimationCollection * collection = [[HyAnimationCollection alloc] init];
self.weakanim = collection;
First this logs nil then it always logs an address. So there are two indicators here:
Memory starts at 9.7MB and goes up 0.1MB every 10 runs of the animation. I tested this to about 12MB. Now, should the memory be freed every time or is it just that ARC (like, say, JVM's garbage collector) only releases memory periodically? That is, maybe it isn't a leak, but instead ARC has not released it yet because I didn't reach a certain amount.
I declared weakanim as weak just to see if the previous animation collection was being released, but the same issue still arises: is ARC not releasing yet?

ARC doesn't work like a JVM. The closest you get is when it uses the "autorelease pool." In this case, objects won't be related until the end of the run loop. If you can see the animation running then the run loop is most likely running and the pool should be flushed periodically.
A better way of showing whether there's a leak would be to put a breakpoint in the dealloc method of your HyAnimationCollection class. If the rest of your investigation is correct, my guess is that it's never called. You probably have a retain cycle in that code.

Related

How to find the real cause of memory warning and how to resolve in iOS app

I have go through many posts related memory management, ARC , memory management techniques like autoreleasepool and using instruments tool to detect which code is causing memory warning but in my case I am not able to figure out the exact cause.
Basic details which you must know about the app:
We have developed an iPad app. In that we have to use more then 2000 images in some case, so when my app launch we do not want to show them placeholder image (client requirement).so to achieve this, we used SDWebImage , store images on disk and later than we are loading images from there.
There are so many core animation I have performed like "Gennie effect", display pop-up and so many other core animations.
We have used ARC in our project and we found that due to memory warning app is crashing randomly.
We have used Instruments "Allocation" for finding the dirty memory.
Previously we analyze the logs and we stored images with SDWebImage in DISK, it resolve that frequently crashing of app, but still app is crashing due to memory warning.
When we go deep in that we found "Anonymous VM" is keep incrasing and not releasing memory when any screen switch in iPad.
Here is the screenshot of profiling of our app on device.
Anyone please suggest tips or coding techniques or any idea by which We can reduce memory load and resolve memory warning.
Any help will be appreciated. Thanks.
In WWDC 2012 Session 242 iOS App Performance: Memory,Apple introduce a way to detect memory problem with Allocations template of Instruments,start from 31 minutes.
1.
Apple suggests push pop repeatedly before take a snapshot of the heap,I prefer push pop just once.
The Snapshot button is Named "Mark Generation"
You should take Snapshot multiple times.
2.
If your memory grow between each Snapshot,You can dig into one of the snapshot except the first one.
Sort the objects by Persitent,you probably has seen your problem ViewController (if you only push pop once).Or you can just search for it.
3.Now you can dig into the call tree ,find and fix the problems.
4.You can use this technique not just for push pop viewControllers,but also scrolling in a tableView ,perform a databaseSearch and any other cases.
Wolverine,
Not saying this is an absolute answer to your question, but might provide you some hint to resolve the problem.
My Case :
Today morning while debugging the memory crash just as your's in one of my chat application I came accross a similar scenario. I am using SDWebImage as well to cache and load the images for the subsequent usages.
Initial observations made me believe that it is the crash because of SDWebImage. Soon I realized that crach was rather because of a very simple issue.
I had never tested whether my viewController's dealloc is getting called or not. On putting a breakpoint in dealloc I realized dealloc was never being called (for various reasons which I resolved now).
As in your case, my chatViewController though not loading 100's of images used to load 8 - 10 images at a time and crash started appearing when I used panorama images rather then normal Images.
Conclusion :
My viewController had strong reference to UIImageView which was loading heavy images and as dealloc was never called for my ViewController all the loaded images were never realesed which resulted in memory crash.
As I was loading heavy images I was performing several calculations to reduce the size of image. Most of the calculations involved repeated creation of image from NSData using UIImageJPEGRepresentation. Repeated allocation of data and image holder variable added to memory consumption of the app.
As my ViewController involved number of API calls, I had created a singleton reference service class to which I used to pass complitionblocks and unknwingly I had used self inside the completionblocks passed to the methods. Which actually contributed to ARC reference count increment and never let my view controller to get deallocate.
Way to Debug
As you have already mentioned in your question that you are loading loads of images in your ViewController make sure the viewController gets deallocated properly and releases all the memory loaded by all the ImageView's present in ViewController.
If your ViewController's dealloc is not getting called then as just a way to test (remember not a solution) in viewWillAppear set all the imageView's image property to nil and forcefully clear the memory loaded.
If ViewController dealloc not getting called turns out to be the culprit, try finding where you are sending self as strong reference. If found try using weak self.
I know its not a absolute answer to your question. Just sharing my experience with you. Hope this will atleast give you hint to solve yours.
Try Infer it may helpfull, it reports memory leak problems in iOS and C code.
A static analyzer in deployment at Facebook, where it is used as part of the development process for mobile apps. Infer targets critical bugs such as null pointer exceptions, resource leaks and memory leaks — problems which lead to crashes or performance degradation in apps.
It looks like some object in your app is not being released, probably due to a retain cycle. Check all references to delegates are weak references.
Also check blocks and ensure a strong reference to self is not captured in a block. If Object A keeps a strong reference to Object B, then passes a block containing a strong reference to self to object B, both objects are potentially locked in a retain cycle.
Use this syntax to pass a weak reference to self:
__weak typeof(self)weakSelf = self;
[doSomethingWithBlock:^() {
__strong typeof(weakSelf)strongSelf = weakSelf;
if (!strongSelf) {
return;
}
[strongSelf doSomething];}];
in Swift do this:
someObject.doSomething() { [weak self] in
self?.doSomething()
}
or use [unowned self] - both create a weak reference to self, in the case of [weak self], self is optional
To ensure all your objects are deallocated as expected, put a log statement in your dealloc / deinit functions and check they are really being called.

iOS custom keyboard extension - Memory Limit

I am developing a custom keyboard in which I'm ridiculously facing the memory issue. I did all kind of instrumental observation and came to the conclusion that iOS is preserving the memory every time keyboard is appearing and invalidating. I'm very much frustrated of this behaviour because as in dealloc I'm already releasing all of my DMA though my project is in ARC.
Scenario is something like this:
When I starts my keyboard for the first time it consumes approximately and after some operation it use to increase upto 30 MB and then I invalidate the keyboard. Again when I'm reloading it at that moment it starts from 30 MB which is totally unexpected and due to which after some transitions there is memory pressure and extension gets crashed.
It will be very much helpful if anyone can suggest some idea to manage memory pressure.
Short answer here is that you have a memory leak.
If you are writing you extension in Swift, add a break point to the deinit method in view controller that inherits from UIInputViewController and see if it gets called.
If you are writing your app in Objective-C then you can do the same thing from the deconstructor.
I too struggled with this and from my experience, the only thing that will stick around after closing the keyboard is some Core Data stuff. Other then that, if all your objects are owned by the primary view controller (UIInputViewController) then they will go away if they are no longer referenced.
If you still see a large amount of memory being used after the deinit is called then you have a leak elsewhere. Watch out for retain-release cycles and be careful with closures in Swift. Those are usually the culprits when it comes to memory leaks.
Without seeing any of your code I can't really provide any more specific information here.
Good luck!

setNeedsDisplay, drawRect or CALayer causing dispatch_continuation_alloc_from_heap malloc memory leak iOS

I'm experiencing a memory leak in my application and it seems to originate from CALayer. It looks as though it only affects old iPads; I see the problem with iPad 1 & 2, but iPad Air is ok. I have a crash report from an iPad 1 showing that my app was 'jettisoned' due to insufficient memory, this leak is my main suspect.
Background
During operation setNeedsDisplay is continuously called every 40ms by the network thread on various UIViews to update their visuals, see function below.
- (void)setNeedsRepaint
{
[self performSelectorOnMainThread:#selector(setNeedsDisplay) withObject:nil waitUntilDone:NO];
}
Simulating iPad2 and using the allocations instrument, I see that every time setNeedsDisplay is called the malloc 64 reference count permanently rises. The responsible library is libdispatch.dylib and the caller is dispatch_continuation_alloc_from_heap.
The iPad Air simulator doesn't show this issue, in this case the malloc 32 reference count only temporarily rises.
I am seeing the malloc 64 reference count rise even on occasions where setNeedsDisplay originates in the GUI thread and isn't dispatched via performSelectorOnMainThread.
Below is a screen shot of the allocations instrument. The malloc marked 3 is the leak in question. The mallocs marked 1 & 2 leak much slower, but are still a slight concern.
Steps taken
To rule out a memory leak in drawRect I commented out all the code between the braces, but the leaked memory still continues to accumulate.
If I don't override the drawRect method I don't see the leak, but I need to in order to draw and update my view. Nor do I see it if setNeedsDisplay is not called, I can call a dummy function instead via performSelectorOnMainThread with no memory leak.
I've tried using blocks and dispatch_async instead of performSelectorOnMainThread to run setNeedsDisplay on the GUI thread.
I also tried reducing the app down so that setNeedsDisplay is only repeatedly called on a single view. Then removing all pointers to that view so ARC cleans it up in the hope that the stray mallocs might get cleaned up with it.
I've tried setting the CALayer contents directly instead of calling setNeedsDisplay. It renders, but the malloc count rises in exactly the same way.
self.layer.contents = (__bridge id) _dummyCGImageRef;
After reading this I thought the leak maybe due to the queue becoming swamped. However, slowing the rate of my function call by 10 just made the memory leak grow 10x slower.
Conclusions
The leak really seems tied to CALayer rather than the dispatch queue and performSelectorOnMainThread. It looks like this issue is fixed in later iPads, but I still need a workaround for older models.
Questions
Has anyone got any tips for debugging this?
Is another instrument better suited to finding the exact cause?
Is this a peculiarity of the simulator and what I'm seeing isn't the reason my app is jettisoning?
Anyone know what's causing this? Is this an historic bug since it doesn't affect iPad Air?
I there a subclassing trick I could do with CALayer to prevent the backing store allocating memory, or another way I update my view visuals?
Thanks.

Dealloc called but live memory not decreasing

I have three UIViewControllers and all of their dealloc methods are called whenever I dismiss them. This is exactly what I want to happen so that the memory won't balloon up.
However, when I ran the Profile to test the memory usage and for some leakages, I noticed that even if the dealloc was called, the live memory doesn't decrease somehow. What's more is that it keeps on increasing whenever I switch from one UIViewController to another (which is expected by the way). Sometimes it will decrease, but only a few memory will be decreased.
I am sure that the dealloc methods of each UIViewControllers were called since I put a log inside of the methods. Also, no there are no leakages recorded when I used Profile.
So can anyone explain why the memory does not decrease at all?
As someone else said, without seeing your code is a bit hard to figure out what's going. So instead I will leave you this & this articles about analysing the heap using instruments.

Memory Issue with ARC

I've used ARC to build a fairly simple application. However, I'm running into a memory deficiency, but I can't figure out what is causing it. Since I can't clarify what is causing it, I have a few specific details and questions.
The problem ensues when I try to load a new View Controller. This view controller hosts a number of images and, when loaded, will add a 3-4 minute audio file to an AVAudioPlayer in a singleton class I have.
The problem occurs when the view controller is pushed and popped 8-10 times. When the view controller is popped, I call stop on the AVAudioPlayer and return all relevant objects (including the AVAudioPlayer instance) back to nil.
I don't really understand what could be causing the memory leak, or what else could be ravaging the device memory, but I do have a few specific questions.
When stopping the AVAudioPlayer, will that still allow for a proper release in the memory?
Will setting the AVAudioPlayer pointer to nil after calling stop prevent the system from releasing certain data from the device memory?
Shouldn't anything, in ARC, be released when the owner(s) are deallocated (I'm asking about all of the views and data in my UIViewController that gets popped off the stack)?
Are there any issues with AVFoundation or AVAudioPlayer in ARC that I should know?
Is calling stop the wrong way to end an audio session / have it be released?
EDIT: I have started using the instruments tool in order to track my allocations and leaks. There aren't any memory leaks, or so the tool says, but the application will crash, nearly regardless of the live bytes. The application will crash when the total RAM used is over 200MB (210-230MB - my device has 256MB of RAM). My new question is will the total bytes allocated (even if they're not live) affect the memory crashes? If so, how can I prevent this?
Here is an image of a run that crashed. You can see the clump of memory warnings at the end.
Q) The problem occurs when the view controller is pushed and popped 8-10 times. When the view controller is popped, I call stop on the AVAudioPlayer and return all relevant objects (including the AVAudioPlayer instance) back to nil.
A) Add a dealloc method and log the dealloc, so you know nothing is retaining those, then look for these in the console:
- (void)dealloc
{
NSLog(#"MySpecialViewController getting dealloced!");
}
if you don't see these something is retaining this object - a delegate possibly.
Q) I don't really understand what could be causing the memory leak, or what else could be ravaging the device memory, but I do have a few specific questions.
A) You should be using ObjectAlloc in Instruments (and Leaks). These are really easy to use - run the project with them in the Simulator, just use the defaults, and you'll get a lot of good info right away. You can see WHAT is leaking which should really help.
Q) When stopping the AVAudioPlayer, will that still allow for a proper release in the memory?
A) No. You have to set your strong ivar/property to nil (which you said you are doing). I just checked and the AVAudioPlayer does not retain the delegate. That said, as a general rule, when I am shutting down anything its:
[something stop/cancel/etc];
something.delegate = nil;
something = nil;
Will setting the AVAudioPlayer pointer to nil after calling stop prevent the system from releasing certain data from the device memory?
Q) Shouldn't anything, in ARC, be released when the owner(s) are deallocated (I'm asking about all of the views and data in my UIViewController that gets popped off the stack)?
A) If the only thing that is retaining the ViewController, for instance the navigationController's viewControllers array, then yes, your viewController subclass should get dealloced, and all strong properties and ivars will too.
Q) Are there any issues with AVFoundation or AVAudioPlayer in ARC that I should know?
A) I know of none, and since this is a popular class expect your problem is in your code.
Q) Is calling stop the wrong way to end an audio session / have it be released?
A) If it were me:
[avPlayer stop];
avPlayer.delegate = nil;
avPlayer = nil;
EDIT: If you are getting memory warnings when your app is running, you are leaking or consuming some huge amounts of memory. Put a breakpoint where you get this warning, stop your app, and look at your allocations. I've never gotten a memory warning for real (I use ARC exclusively)
One area where it is easy to run into memory trouble while using ARC is situations where you are interacting with a Cocoa Touch API that requires the main thread from a background thread.
It doesn't sound like you are up against this, but if you start seeing inconsistent behavior (e.g. what appear to be random crashes, objects going out of scope prematurely, etc.) it is worth investing some effort to see if you are interacting with Cocoa Touch from a background thread.
Sometimes callbacks from Cocoa Touch (that one might assume would be on the main thread) aren't (we have seen this in some Game Center API's).

Resources