Real Memory Constantly Increasing - Removing Subviews from View - iOS (ARC) - ios

I have an iPad app which is crashing on iPad (First model) as it is running out of memory.
In the app I have a main view which adds as subviews about 20 UIScrollViews (custom class) each containing a UIImageView and UIImage. When the user moves to the next page, I remove all these subviews from the superview and then add 20 new UIScrollViews to the same view.
If I profile the app for allocations and memory leaks everything is ok - the memory allocated stays at about 2MB while the user scrolls left and right.
However if I look at the real memory usage in the Activity Monitor I can see that every time the user moves to a new page, the real memory increases by about 20MB. Eventually after a few new pages the app size hits 150+ MB and crashes.
Can anyone suggest what might cause this type of behaviour and how I can further troubleshoot this ?
Just a bit more info on the app structure :
In view did load the images are loaded into an NSMutableArray using initWithContentsOfFile.

You should not be maintaining these images in an array. Images consume a disproportionate amount of your limited RAM. There are a couple of approaches:
If you want to keep it simple, just don't store the images anywhere. Load the image property of the UIImageView by loading the image via initWithContentsOfFile and call it a day.
If you want some RAM caching for performance reasons, you could use imageNamed instead of initWithContentsOfFile. When the app receives a memory warning, the cache will automatically be purged.
I'd be inclined to use initWithContentsOfFile, but then manually cache in my own NSCache (which is like a NSDictionary, except you can set a countLimit of how many images it should hang on to).
By the way, you don't describe what technically happens when "the user moves to the next page." If you're simply refreshing the existing controls on the existing view controller, then everything is probably fine (once you fix the NSMutableArray problem I discuss above). If you're pushing/presenting to another view controller or scrolling controls off screen but neglecting to remove the old ones from their superview, then that will also cause problems. You might want to clarify what you're doing there.
Bottom line, you just need to make sure that when you go from one page to another, that you're not maintaining strong references to any old images or controls.

Related

IOS App keeps Images in Memory

I have an app that has two view controllers with images
when I launch the app the memory increases and when I then segue to the other view controller and load the 2nd image ( I have a button to do this ) the memory goes up again.. this is what I would have expected..
However, when I dismiss the 2nd VC controller or removing the image in the 2nd VC via a button, and then dismiss the controller , the memory never goes down.
why is this, with an app with lots of images it could get large.. how do I release the memory of the 2nd VC or at least the memory of the 2nd image.
Im looking at memory under debug navigator in Xcode 8, when running the app.
xcode project can be found here , very simple
iOS will cache images. The documentation for UIImage(named:) says:
Discussion
This method looks in the system caches for an image object with the specified name and returns the variant of that image that is best suited for the main screen. If a matching image object is not already in the cache, this method locates and loads the image data from disk or from an available asset catalog, and then returns the resulting object.
The system may purge cached image data at any time to free up memory. Purging occurs only for images that are in the cache but are not currently being used...
Special Considerations
If you have an image file that will only be displayed once and wish to ensure that it does not get added to the system’s cache, you should instead create your image using
imageWithContentsOfFile:. This will keep your single-use image out of the system image cache, potentially improving the memory use characteristics of your app.
Note, you don't control when this cache is freed. The OS does that as it sees fit (and generally in response to memory pressure).
Bottom line, we often don't worry about inherent caching by UIImage and simply ensure the app doesn't have its own memory issues, e.g. make sure deinit is getting called and/or use the "Debug Memory Graph" feature in Xcode to watch memory graph. Or if you want, programmatically set the image using UIImage(contentsOfFile:).

Best image caching strategy in iOS

In my app, I have a UITableView which displays fairly large images and loads a moderately designed Xib file to display it in. Each image is around 700KB to 1MB in size. The flow is virtually never ending, it loads more and more as we scroll down. So you can imagine that I am running into memory issues.
I have tried using SDImageCache and NSCache. The former used disk memory for caching images. In both cases, the caches somehow didn't clear images automatically. I had to manually clear them when I got a Received memory warning prompt. And each time I clear these caches, the memory freed seems to be lesser each subsequent time.
Now I confused as to which cache strategy I must use for such a long list of images. Might I be having some leaks somewhere? They certainly didn't show up when I profiled the app.
P.S.: I am loading the images from the web. Just to be clear.
From the docs:
UIImage
+(UIImage *)imageNamed:(NSString *)name
Discussion This method looks in the system caches for an image object
with the specified name and returns that object if it exists. If a
matching image object is not already in the cache, this method loads
the image data from the specified file, caches it, and then returns
the resulting object.
So I guess leaving this to the UIImage class is a good approach.
Hope this helps!
As we implemented it in both Android and iOS: once you can show on the screen only 2-3 images.
Load in memory 2 more for the downwards scroll and 2 more for the upwards one. So you have in memory 7 images. Display them. The other images must be stored in files (when you download them). If the user scrolls too fast, do not show all the sequence of the images, instead show some "loading" icons in place of the images. When the scrolling stops, show the appropriate image + the previous one + the next one + prepare 2 more (for upwards scroll) and 2 more for downwards scroll.

How to reorganize iOS project to avoid memory issues

I am building my first project that is an interactive ebook app for the iPad
I started with the Single View App template from XCode
So far, the project is mostly a series of block animated transitions between UIImageViews and MPMovieController videos, very serial so far
Everything is coded within a single view under a single view - the image views fade in and out with alpha animations
I am beginning to run into memory issues. I've used memory instruments and see that most everything is loaded into memory at the beginning (images from the InterfaceBuilder) aside from some videos instantiated at runtime
My question is - how should I reorganize my code to better utilize memory? Should I separate into different views under one view controller, or have multiple view controllers?
And which might be the most straight forward to implement?
Images are very memory-intensive. So:
Do not load an image until you actually need it (for display). When you are done with it (the image view is no longer visible), release it (by setting that image view's image to nil). Do not maintain the images in an array or anything like that. Do not create the image views preloaded with images in advance in the nib.
When you actually need an image for display, load it in code using imageWithContentsOfFile:, not imageNamed:. Thus you prevent caching of the image.
It is a waste of memory to work with an image larger than the display size. If these images are large, you can save a lot of memory up front if you load the image at the actual size needed for display. This is easy to do with Image IO framework and CGImageSourceCreateThumbnailAtIndex.
I think you need to use multiple view controllers and separate your code in small separated views and objescts that controll you app flow..
On the one hand it's better to have multiple views and so on..but it's a pain to rewrite code you worked on (unless it's absolutely necessary).
In my opinion if you don't have anything unnecessary in memory (i.e. when you take a view off screen you release the memory it used) you don't need to do anything.
After all, even if you split the code as it should have been, if your memory management is good, it will take the exact same memory.
You should be able to do this with a single view controller:
Load your images lazily from code. Keep an array of the image names rather than the images themselves, and load them just before you need them.
Make sure your images aren't larger than they need to be.
Recycle your image views. If the user won't see more than two image views at a time (including both the from and to in a transition), you should only have two image views.
Don't worry about whether the images are cached; iOS's caches are designed to release their contents under stress. That said, do not implement your own caching system. You might not release images properly under stress. If you need caching, use NSCache.

UIWebView memory leak

I have an iPad app (IOS 4.3 & 5.0) that is creating a UIView with at least 2 subviews every time the user pages forward or backward. The 2 subviews are UIWebView objects.
On every relevant swipe the old UIWebViews are removed and deallocated properly (removeFromSuperview then stopLoading and set delegate to nil) and the parent UIView is deallocated. I can confirm that both parent UIView and the 2 child UIWebViews are absolutely gone.
I can see the retain count on the webviews as they are being removed and I am quite sure that they are indeed removed every time.
However my memory allocation continues to increase on every swipe by ~200-350k . No leaks in instrument but I can see the memory usage going up slowly.
On iPad 1 the app eventually (within 6-10 minutes of moderate usage) receives multiple memory warnings and is terminated. LowMemory crash log...etc is generated.
We use stringByEvaluatingJavaScriptFromString and loadRequest to populate the Webviews. Memory usage creeps up even when nothing is injected or loaded into the webViews.
Is anybody experiencing this kind of behavior with UIWebViews ? Has anyone dealt with this successfully ?
Thoughs, comments & answers would be greatly appreciated.
Try to use Instruments but with the "Allocations" template and watch the "# Living" columns for UIWebView. I usually use it like this:
Profile app with Allocations template
"Warn up" the app by going thru all tabs, scroll around etc.
Press "Mark Heap", this will create a "Baseline" heapshot
Do the thing you think causes objects to stay around
Press "Mark Heap" again, this will create a "Heapshop #" heapshot
Inspect the objects in "Heapshop #" which will show size and number of objects created and alive since the last heapshot.
Goto 4
Not aware of any leak, but if you are destroying and re-creating the same view hierarchy every swipe, why not store the views and re-use them instead?
Regardless of whether they leak, webviews are computationally expensive to set up, so re-using them and just reloading the content should give you a performance boost, and may solve your leak as well.
are you still seeing this issue? I traced something which looks like unbounded memory usage (not necessarily a leak, but I get low memory warnings and eventual process termination) by calling stringByEvaluatingJavaScriptFromString over and over:
[webview stringByEvaluatingJavaScriptFromString:#"something()"];
It seems like there is something odd there.

iPad performance issues

I have this problem with performance of my iPad app..
For developing, I use MonoDevelop, which takes care of Garbage collecting. Still my questions are rather generic, I'd say.
OK, I use TabBarController with 5 NavigationControllers. Inside nav controllers there are some controllers, whose views are TableViews or ScrollViews. Next child is always just regular view.
I have a few questions:
1) TableViews never scroll smoothly. I have some alpha transparency, but since I did my graphics in Photoshop and not programmatically, this transparency should not cause much problems. It doesn't matter whether I have few or many results in table.
On the other hand, I have ScrollView which serves same purpose, i.e. to be a table with different layout and buttons have Photoshop generated transparency as well. It works perfectly.
For tables I applied DequeueReusableCell() which works fine (I see that memory usage is not increasing after scrolling). So why would tables scroll so jerky?
2) My app supports rotation. When I scroll table or scrollView and simultaneously tilt the device a bit, I get maybe 1 or 2 FPS. What is the best way to implement rotation? As I understand, ShouldAutorotateToInterfaceOrientation has to be overridden in all controllers in NavigationController chain. Also, I need to add observer in View I want some changes to happen. Do I have to use BeginGeneratingDeviceOrientationNotifications() in all views or is it enough to do it in Main.cs? Maybe this slows it down?
3) After some time app starts getting memory warnings and then crashes eventually. I tried to read logs and run app with Instruments, but can't find the cause of crash.
4) What exactly happens to a View popped from NavigationController stack? I can't reuse it. But could it be that Monotouch (or me) doesn't dispose it correctly?
I have almost same app for iPhone without support for rotation which never crashes. I think I'm doing something wrong with this rotation, but I'm not sure what.
Any help will be appreciated the most. So, thank you in advance.
Regards
1 - transparencies are always a problem. Even if you're not rendering the images in code, the phone still needs to do the compositing of the image, and that may take a lot of time. UITableViews have to calculate the final composite image every time a new cell is displayed, or the table is scrolled, while UIScrollViews can calculate only once, since the image won't change. So be very careful about it, turn the transparency off, and check if performance improves.
2 - You shouldn't need to notify every uiview in your application. Receive the notification in the controllers that you want to update only, like for example if you want to rearrange items in the UIViewControllers view.
3 - you have one (or many) memory leaks. My guess is that MonoTouch probably can't garbage collect UIViews or UIViewControllers, because they're still being linked from somewhere in UIKit, like a UINavigationController
4 - UIViews are not disposed by UIKit until the app gets a memory warning notification.
Like Eduardo said, alpha transparency in Views comes at a price. There are some tools that you can use to identify the bottlenecks discussed in these WWDC 2011 talks from:
https://developer.apple.com/videos/wwdc/2011/
iOS Performance and Power Optimization with Instruments
Understanding UIKit Rendering
In the "Debug" menu of the iOS simulator you can find various debugging tools that will color different regions of the screen indicating where some problematic rendering is taking place. The WWDC 2011 talks show what you can do to fix those problems.
For your memory problems, it is very likely that you have something pointing out to your objects around, so you need to make sure those objects are gone. While we currently are not shipping our new profiler for MonoTouch that can show the source of the problem, I wrote a "poor man's" debug utility that will help you narrow down which objects are alive. It is available here:
http://tirania.org/tmp/HttpDebug.cs
Call HttpDebug.Start () from your application and as you run, connect with a web browser to http://localhost:5000 to get a list of live Objective-C objects surfaced to C#. The tool is not perfect and shows a lot of irrelevant data, but it would at least give you an idea of what is going on.

Resources