Prevent UIWebView allocating to much memory - ios

I have a problem with UIWebView. I am using this component for loading normal web pages on iPad/iPhone. UIWebView is presented in modalViewController. Some pages are very memory hungry and some also have Flash content.
The problem is that sometimes on some pages I get memory warning
Received memory warning. Level=1
When this happens and when I close this modalViewController (which has page loaded in webView) than the previous view reloads itself automacially - method viewDidLoad is fired again.
I suspect that some pages in UIWebView consume to much memory and than application release memory of its views, but does not crash.
Is there a way to limit memory consumption of webView or is there any other way to avoid this memory warning?
Thanks!

You have very little control of the memory usage of UIWebView objects. You also have very little control of the overall system memory usage. So there is no way to avoid memory warnings. iOS expects your apps to behave properly when receiving memory warnings, so your viewDidLoad method should be written to handle rerunning after a memory warning.
The only things you can do to limit the memory usage of a UIWebView is to have it view simple web pages. It looks like from your question, that's not an option.
Edit: viewDidUnload is called during low-memory conditions. This method is expected to free up anything that's easy to recreate in the viewDidLoad method. Don't release the state information you want to show the user when this view is returned to the screen. Then in your viewDidLoad method check all the objects you create. If they are nil, they need to be initialized, otherwise this isn't the first time your viewDidLoad method was called, and you shouldn't initialize your objects agin.
In other words: viewDidUnload handles low-memory situations and viewDidLoad should not assume it is run once.

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.

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.

Main View gets dark when coming back from Background

I am using RouteMe's library and services to display maps.
The main ViewController holds an *RMMapView that inherits from UIView. Basically it just fills up with tiles.
When my app goes to background, and after a while, after other apps are loaded into memory usually, comes back to foreground, The main mapView goes completely black and I can't see anything except for my UI.
(I guess due to lack of memory)
How can I prevent that from happening ?
Thanks!
you cant prevent a Memory warning from happening, however if you are 100% sure that you cant handle the memory warning in some view controller and to stop the call to viewDidUnload remove the implementation of didReceiveMemoryWarning in your view controller
Please note that disabling the viewDidUnload is not recommended, you should reflect about your memory usage and present a better memory management technique

iOS crash - no leaks, NSZombie enabled and doesn't breaking on exceptions

I am writing an iPad app which uses an AVPlayer to display a video. There's buttons to jump to various parts of the video, and when the user rotates the device, I change the size of the view which holds the AVPlayer layer.
My problem is that after a certain amount of device orientation changes and jumps around the video, the app crashes.
I have NSZombie enabled - this doesn't break.
I have a breakpoint enabled in my code to catch exceptions - this doesn't break.
I have run instruments and the code isn't leaking.
Allocations simply shows the "Overall Bytes" growing and growing with every action until it hits 14 meg and the pad crashes.
I feel like I have no way of getting to the bottom of this. Am I missing some trick to solving this? Does AVPlayer need some special treatment when being released?
ANY HELP, MUCH APPRECIATED.
Use instruments to check your Allocations. I recently had a very similar problem where there were no memory leaks but my Overall Bytes kept growing every time I launched a particular ViewController (and it would eventually crash).
It turned out that the ViewController itself was a strong reference as a delegate to another class (oops) and each time I dismissed the ViewController that other class still had a reference to it. Therefore each time I launched and dismissed this ViewController I would create another instance of it that would never die (and never leak).
Your exact problem may be different but you should be able to see the reason for your Overall Bytes growing by checking out your Allocations.

iOS not always calling didReceiveMemoryWarning

I'm looking for help with a very specific memory-management issue where didReceiveMemoryWarning doesn't appear to be getting called in cases where it should be.
I have a straightforward app that's a story with pages. I have an outer view/controller that manages the page views/controller. Each page view has a picture on it of decent size (200-300k). It's large because it's a universal app, so they're all 1024x768, then get scaled down for the iPhone. I have implemented didReceiveMemoryWarning to release unused controllers (whatever's not showing at the time). The app works fine when didReceiveMemoryWarning gets called, but it does not always get called. On the iPod Touch 2G, if I'm going from page to page fast, it will often just kill the program without calling didReceiveMemoryWarning (I put a breakpoint there to see). On an iPhone 1G which has the same amount of RAM, didReceiveMemoryWarning gets called at reasonable times and I never run out of memory.
The log prints "Received memory warning level 1/2" as expected right before my code does get called, but I don't see it in the logs in the iPod Touch 2G when my app gets killed without a chance to free up memory.
I've used static analysis and the leaks tool and the memory profile looks good. I don't think leaks have anything to do with the problem. Rather, the problem is that my program doesn't get the opportunity to free up resources when memory is tight. I do want to keep unseen pages in memory when there's enough memory - it allows for quick paging and makes the pan gesture for changing pages work responsively.
Has anyone else seen this? If anyone has hints, I'd appreciate it. I'm also curious if anyone knows under what conditions didReceiveMemoryWarning should get called. Is it possible that my program is gobbling up so much memory so fast that iOS doesn't have an opportunity to free up memory?
Memory warnings appear to come too late when allocating a lot of memory "too" quickly, especially if the app doesn't spend enough idle time in the run loop between allocations.
Try preflighting (attempt to allocate and then release) memory, and return to the run loop, maybe a half second before you really need the memory.

Resources