I am trying to find the source of a memory leak as detailed here :
Unable to Release Quartz 2D and Core Text created Images
When I use instruments I can see that there is something called CG Raster Data steadily growing in size which is never released.
Does anyone know what could be causing this and how to remedy ? It looks like this might be some sort of image caching, but is it possible to flush this from code ?
I had the same issue with CG Raster Data memory increasing by simply pushing and popping a view controller repeatedly. I spent a while thinking it was an issue with some drawing code. I finally tracked it down to a delegate not weakly referencing the view controller that was being pushed and popped, so when I popped the view controller, it wasn't being deallocated. The CG Raster Data happened to be the biggest part of that view controller's footprint, so I mistakenly attributed the problem to that initially, when it was really the view controller itself that wasn't being released (therefore, not releasing its views, some of which had CG Raster Data).
In short: if you're seeing memory leaks with CG Raster Data, look at view controllers that might have views with them, and make sure that they are being released.
Related
I'm creating a project which uses a UICollectionView. As the user selects a cell this slides them to another UICollectionView of similar nature. Ive been noticing that no matter how I go about this I wind up with mountains of memory usage.
I've been experimenting with placing UICollectionView's in full page UICollectionViewCell's so as to take advantage of the reusability of UICollectionViews. The downside of this approach has been memory retention as the CollectionViews are never fully deallocated. Ive also heard that it is not the best practice to put a UICollectionView in a UICollectionView.
I've experimented with UIPageViewController's containing UIViewController's with the UICollectionView inside. This is more efficient as the UIViewController's can be deallocated as the user swipes back however as long as the user continues to select cells and create new view controllers the memory grows unbounded looking like a mountain.
As a bit of a hybrid I attempted as well to put ViewControllers containing UICollectionView's on UICollectionViewCell's. This method seemed to work best but I had to deallocate the view controllers manually as the user swiped.
Are there any strategies or libraries anyone could recommend that would fit this problem. How can I keep the memory down. I understand I'll need some kind of reusable views.
Ive been looking into this Library so far thank you in advance for all of your advise
Parchment Library
I think I understand what you're saying. You have a UICollectionView that can drill down to another UICollectionView, leaving the first one and its backing data retained until you come back and pop it off. Drilling down further and further allocates more and more memory until you back out.
I'd keep things as simple as possible. Solutions like putting a UICollectionView inside UICollectionViewCells can cause your code to get unnecessarily complicated, resulting in new issues and code that's programmer-hostile. If the user experience that works best is a collection view UI that you can drill down into infinitely, then go with that paradigm.
Your issue is not with UICollectionViews, it's in managing your backing data's memory use. That could be done a few ways. It would help to know what kind of data you have that's so large, and what "large" means, but here are a few approaches that come to mind.
One idea would be to unload any large data when you go to the next screen. For example, if your datasource uses an array with a bunch of large images, clear them out when the next view is pushed. Reload the data when your view appears again, or do it lazily when the view's cells need it, whichever works best for you. This would be the easiest approach and probably take care of your memory concerns.
A second approach would be to use one UICollectionView and use custom animations so it looks like a new collection view is pushing/popping from an old one, when in fact you're just changing the data for the collection view and reloading. You could even provide animations that are more interesting than pushing/popping.
On top of either of these approaches, you could implement the UICollectionView prefetch API calls to load data just before you need it. That will reduce your memory footprint even further.
All of these approaches assume that you can load the data to display from storage-- that it's not just in memory from recent webservice requests. Your users are guaranteed a miserable experience if your app has to keep requesting the same large data from the web over and over. So, if you don't have the data stored locally already, set up a cache.
Regardless of the approach, this is something you should be able to handle without adopting a library. UICollectionViews are designed to be memory friendly. Your issue is really in determining the best way to manage your backing data's memory use.
In my iPhone application utilizing ARC pushing certain view controllers leads to large memory allocations which are not released. Most of the Live Bytes have the header VM: CoreAnimation
I have tried wrapping various pieces of code, such as pushing the view controller, with #autoreleasepool { } but it doesn't make any difference. Setting the view controllers to nil once they are no longer needed also doesn't help.
Your help and advice will be much appreciated!
UPDATE
I realised that the timing of the memory allocations coincided with a detail view with a CorePlot chart being pushed from a table view. The detail view was also referenced in the table view's header file. One issue was that I was setting the detail view to nil and then reallocating it prior to it being pushed. If I instead initiate the detail view once only when the table view is first loaded, and then refresh its contents before each push, the memory allocation only happens once.
However, I have not been able to completely solve the issue as there is still a large memory allocation when the detail view is first pushed, which is never released.
Perhaps you are using CoreGraphics framework for drawing something on view's, but you are not releasing coreGraphics object. CoreGraphics object is not released by ARC it must be retain/release manually.
I discovered that the memory issues were caused by the creation of new Core-Plot charts that were not releasing their memory when I attempted to deallocate them.
I managed to improve performance using this function when I try to deallocate the charts:
[graph removePlot:plot];
This has been sufficient to significantly improve the situation, although I am still struggling to get 100% memory release. From reading the Core Plot forums it appears I am not the only one to have experienced such issues...
https://groups.google.com/forum/#!searchin/coreplot-discuss/memory/coreplot-discuss/nWui9VjnMtQ/er2FO3o9syYJ
Part of the app I'm working on involves a UIPageViewController, where each page displays an 'entry' that is stored in Core Data. An entry includes, among other things, some images that are being compressed and stored as NSData. Thus, to load these images and display them on a page, I'm using imageWithData, i.e.
photo.image = [UIImage imageWithData:entry.photo];
The problem is that imageWithData is not particularly quick, and so flipping through pages is not as responsive as I would like. My best attempt at remedying this situation has been to preload a number of the view controllers that are displayed by my UIPageViewController into an array. (Not sure if that's the best thing to do, but there you have it)
So, to clarify, I have a navigation controller, which contains viewControllerA, which then links to viewControllerB - which displays the UIPageView and the entryControllers (one entryController on each page). The problem is that when I use the navigation bar to go back from viewControllerB to viewControllerA, I want viewControllerB's array of entryControllers to be released from memory. But, ARC doesn't seem to be doing so. Therefore, after going back and forth between viewControllerA and viewControllerB a few times, turning a few pages each time, I start to get memory warnings - which ends up clearing the current array of entryControllers, and defeats the purpose of having that array, since the entries then have to be reloaded every time I get a memory warning.
In short, ARC isn't clearing any of the memory I've allocated for viewControllerB when I go back to viewControllerA via my navigation controller. I don't like that. If anyone could suggest a reason that this is happening, or let me know if I'm going about this whole thing the wrong way, it would be hugely appreciated. I'm just trying to speed up the transition from one page to the next!
Thanks a bunch.
The only reason for ARC to not release your memory is that you still are retaining it somewhere. Only you know where that is.
Usually, this is caused by a retain cycle, which can happen easily with blocks.
However, it is just as likely that you are keeping a pointer to the object someplace, in a controller, an iVar, or some collection.
Have you run the static analyzer on your code? It's pretty good at finding some of those things.
What does instruments tell you? It's got some neat tools for finding leaks and retain cycles.
EDIT
You can have as many references to any object that you want. Once the count goes to zero, it will be released.
The problem is that you are holding an array of strong pointers to view controllers as a cache. If you want them released, you have to manually nil those pointers. You are somehow pre-loading controllers into an array. They will stay alive until you unload them.
So, as long as you have a strong pointer to something, it will stay around.
Jody's edit, specifically mentioning setting pointers to nil, is what got the ball rolling for me in terms of understanding, and in the end I was able to figure out my problem by setting certain pointers to nil when my "viewControllerB" disappeared. Along the way, however, I also realized another important point - large images in core data are a huge memory burden, and in iOS 5, this can be remedied by setting an option to allow for external storage. So for anyone else who's a relative beginner like me and might come across a similar memory problem, this is a key way to limit the amount of memory being eaten by managed objects storing large amounts of data - your images (or whatever large amount of data) are saved to file automatically, without you having to do anything different in code.
When I use addSubview method and then removeFromSubview to load next ViewController then after load view some times, my app crash. I have many images on views.
I think my memory isn't released, in spite of I use ARC.
What I should use to make it work? I tried addChildViewController, but then my view aren't loading.
As per memory management guidelines, whenever you say addSubview, the reference count increases by 1 and whenever you say removeFromSuperview the reference count decreases by one. So, if you are removing any view, that you have added to any view, the reference count should be adjusted and should not cause memory leak.
What problem I can foresee is that you are having memory leak in the added view (the view, that you are adding multiple times) and this in order overflowing your memory. Try maintaining the reference counts and it will work perfectly. As an alternate solution, you can also track memory leaks by using instrument tools.
Here is the thing: I have a view, which contains complicated content that need be redraw after related data updated. I use multiple views to implement this, more likely that one large view contains several subviews, and every subview may also have several subviews. All these views override their own drawRect: method.
The question is that the complicated view takes large memory usage, and I want to know why drawRect: cause a large memory usage, so I can optimizing my view.
Is there anyone give me a hand? Thanks.
EDIT: I just noticed you didn't actually say whether you're talking about iOS or Mac OS X. I assumed iOS; if it's OS X you're on your own :P For future reference, it's good practice to tag your question with the OS or framework you're developing for.
Basically, drawRect is the most memory-heavy way of dealing with views. iOS can't optimise the subview system like it normally does because it doesn't know what you're doing, so there's multiple levels of frame buffers that need to be redrawn before the frame reaches the screen. Consider whether entire views need to be redrawn, and seriously consider using the subview layout system (needsLayout: and friends) or Core Animation to do what you need.
If you seriously need drawRect:, don't give your view any subviews. Subviews do not play nice with drawRect. Either do all your drawing in the view you need, or use the layout subsystem or CA.
Finally, last year's WWDC sessions are good help here. Session 131 "Performance Optimisation on iOS" and session 104 "Designing apps with scroll views" both talk about UIView performance. Here's the link to the sessions if you've lost it: WWDC session videos