I am creating an app that presents different locations in street view. But every time a new place is loading, the memory used is increased. This later leads to the app crashing. Is there any way to clear memory of past loaded street views?
The memory goes up every time a panorama is loaded.
1: test memory usage on device and not in simulator
2: remember ARC can free up memory when it decides too. Unless you really tell it to do so.
Did testing on device helped?
Related
I have a universal app that is essentially a list of articles with images and text, and menu under the left side of the app. I have google analytics in, as well as parse's framework.
The only difference between the app on the iPad and iPhone is that the side menu is always visible on the ipad, and a few interface objects are moved around. (different cell layout for the list--same content, though).
The images are loaded asynchronously using a set of classes that I wrote to download/save in an NSCache object and on the disk using a NSOperationQueue. (disk cache is wiped when the user leaves the app). The NSCache is set to max out at roughly 10 mb. (assuming image size is image hight*image width * 4 bytes per image). (code here is identical for both, so it shouldn't be the culprit, but it is a large chunk of the apps memory use).
I was having some trouble with memory warnings/crashing on an older iphone4 running iOS 5.0, so I ran the app with the Activity Monitor Instrument, and noticed something very odd:
On the iPad (an iPad 2 running iOS 5.1) the app launched, loaded the images that were visible immediately, and was using about 16mb of memory.
On the iPhone4 it launched, loaded the visible images and was using about 35mb of memory--way more than I would expect.
In order to check if it was an OS memory issue, I also ran the app on an iPhone5 running iOS6 and it used about the same amount as the iPhone 4.
I checked my media and the storyboard files to see if anything was different at all, and I could not find anything that could change the memory usage in any significant way.
Is there any way to reduce the memory use of the app on the iphone? I can think of no reason it would use so much memory.
Very difficult to see.. as one person stated pay attention that retina devices will use more memory according to the source, if in the bundle you set #2x images it will load them, and they use more memory.
Have tried to profile the Virtual memory using allocations?
Using memory is usually fine even if it fires a memory warning, the problem is how you respond to it, when it comes does it free enough memory? try with the simulator to simulate a memory warning. Pay attention that sim uses more memory than device.
One other point is that since ARC is difficult to create leaks, but it's easier to create retain cycle and abandoned memory. A correct object life cycle should end with object deallocation.
You say that you use NSCache and load images from the net async, I've got 3 suggestion for you :
Do you know the original image size on the source? maybe on the iPad source images are smaller than on iPhone. A correct approach after you download an image will be resize it according to the really needed size (I'm mean redrawing non just stretching) you ca achieve that with Quartz or using ImageIO
I never understood the behaviour of NSCache after memory warning, Apple says that it will flush the memory but after some test on iOS4 (I don't know now) I don't agree. I've created my own subclass that observe for memory warning and flushes memory
Are you totally sure that you are getting back image from the cache ?
I'm using Instruments with the Allocations instrument. I'm testing only a fixed interaction with my app.
I have a navigation controller which goes 4 stages deep. The first two stages are standard table view controllers and the last two are custom controllers with dynamically loaded images.
So I run my app in instruments (via Run with Performance Tool -> Allocations) and do the following interactions:
1. App Loads
2. I wait a bit until allocations graph stabilizes
3. I tap/push into my navigation controller until the deepest level.
4. I wait for the images to load and for the allocations graph to stabilize.
5. I tap back out of the navigation controller until I'm back to the root level.
6. I wait for the allocations graph to stabilize.
7. GOTO 3.
Now what I've noticed is that between each iteration from 3 to 7 the allocations graph shows a slightly higher value. So the overall allocations are increasing even though I'm doing the same thing and all the view controller's deallocs are being called.
So the timeline looks roughly like this:
1. Start: 1mb
2. Push controllers/Load images: 4mb
3. Pop controllers: 1.1mb
4. Push controllers/Load images: 4.1mb
5. Pop controllers: 1.2mb
6. ... etc ... (always increasing slightly)
So my question is does this mean I have a leak or is this normal? Also what does the allocations graph data actually represent? And why is the value increasing even though I'm popping back out to the initial state? I'm worried that if my app runs long enough it will consume too much memory even though all the user is doing is pushing and popping view controllers.
Any thoughts would be helpful.
Is this in the simulator, or on the device?
As it's good to verify a problem exists on the device, as some system libraries release memory more often on the device than in the simulator.
If Leaks shows nothing, it's because you are still holding a reference to memory somewhere even if you don't think you are. To help track that down, highlight a small portion of the graph where the memory is increasing, and select "created and still living". Now you can see just the memory allocated, and start to track down just where the issue is.
If you have the newest iPhone SDK, the version of Instruments it comes with (2.7 I believe) has a HeapShot feature. You can watch some of the WWDC '10 videos for more information, but essentially you take a shot the first time you pop controllers and then again when you pop a second time. It will show you any memory allocations that are different at the two moments.
You probably have a leak. Check the leaks instrument which can help you find them.
Yes, this is a leak. One of your view controllers along the line is missing something.
If you are loading images then there is a good chance you are using [UIImage imageNamed:] that causes the system to cache and may be a cause of your memory use. But in short yes, you have a leak.
I am using an MKMapView in my iPhone application. When I load this view, the activity monitor instrument shows that the real memory of my App is increasing significantly. It keeps going up as you move the map around or zoom in and out. Once the View controller that loads this view is removed, the memory that was allocated due to the usage of the mapView does not get freed up. Is there something that can be done to get all this memory back?
Is this on the simulator, or the actual device? Some parts of the simulator behave slightly differently to the actual device, and the simulator may not be clearing out the cache properly (since it doesn't have to given the amount of RAM on a Mac compared to an iOS device).
Have you checked to see if you have a memory leak using Instruments? (again, you should do this on the actual device, since occasionally the simulator behaves slightly differently, and will show false positives/negatives when it comes to memory leaks)
For what its worth, there are similar related questions here:
https://stackoverflow.com/questions/5935243/mkmapview-rame-et-fuite-memoire-apple
Is MKMapView leaky
MKMapView Memory Leak in iPhone Application
I have an application that is being ejected by iPhone OS for "low memory".
I have passed it thru instruments and I see zero leaks, and memory usage is around 640 kb.
The application crashes when I add objects to the screen.
This is how it works. I have a UIImageView based class that is very simple and add a few properties to the objects. This class is used on the created objects.
When the user taps a button a new image of that class is created and added to self.view.
After about 15 objects added, the application is ejected with low memory warning.
Instruments report no significant memory usage. Even after 15 objects added, the ALL ALLOCATIONS entry never goes beyond 660 kb. Each object can be one out of five 120x120 pixels image.
If it is not object allocation or leaks, what can that be? Please tell me what directions should I follow to locate the problem.
Thanks for any help.
The ObjectAlloc instrument does not indicate all memory usage within your application. Views and other visual elements do not show their full size in ObjectAlloc, so you will want to use the Memory Monitor instrument to see the actual memory size of your application at any given time.
Also, just because Instruments does not report leaks does not mean they aren't there. Run your application through the Clang Static Analyzer to take another look for potential memory leaks (via Build | Build and Analyze under Xcode 3.2 or by downloading the standalone tool). Again, even if this passes and you still see continually increasing memory consumption you have a leak somewhere.
You mention using Quartz drawing in your comments. You need to remember that Core Foundation objects used in Quartz also follow a specific memory management model, where everything you create with a function having Create in its name must be released using a matching function like CFRelease(). This may not show up as a leak if you forget this, but it is.
Leaks are not your problem. Over-retention is.
Look at Object Allocations. If that graph just rises and rises, your app will be killed. What make the iPhone especially angry is when you are told to let go of some memory (low memory warning) and no memory is freed. Your code may just be an extreme case of this, but you should free up SOMETHING when you get this message.
I discovered the problem had nothing to do with my code. Every time I use quartz on the iPhone I have this kind of problem.
Quartz has a serious problem that has to be fixed. As far as I detected, it gets chunks of memory to perform drawing and does not release them even if you release all variables and references you use. Even if you put all variables nil.
Quartz is a memory eater and a source for crashes.
Here is a project I've created to demonstrate how Quartz can crash your project. Look for a method inside inside MyClass.m, called imageWithBorderFromImage. This method uses quartz to draw a dashed border around the object. Run the project and click several times in the button. Every time you click, a new object is added to the screen, on top of the previous one. After about 20 clicks the application is ejected by springboard. Before that you will see LOW MEMORY warning on console.
Before telling me that the problem is too many views created, disable the quartz method and see that the application does not crashes anymore. In fact I was able to click 80 times and was still able to continue clicking, but I stopped the app.
Download the project QuartzNightmare here
I'm working on an iPhone game that uses an MKMapView as the playfield. After only a couple of minutes of play the app inevitably starts to get sluggish and eventually crashes due to low memory. After digging around the culprit seems to be that the map view constantly demands more memory. The game requires a lot of zooming and panning of the map so I can only assume that the map's cache of tiles just keeps growing until it runs out of memory. Is there any way to force the map view to flush it's cache of tiles or contain it's memory consumption?
* NOTE: This answer is only relevant to iOS 4.1 and lower. The problems described in this answer were mostly fixed in iOS 4.2 *
I've been doing some digging on this as my app uses both the map and also has other features that demand high RAM.
I haven't found an answer, but a workaround. MKMapView's memory demands escalate exponentially as you zoom closer in to an area, and pan around within that zoomed in area.
There are two levels of MKMapView tile cache. One manifests itself as a Malloc ~196kb in Instruments, the other is NSData (store) of varying sizes.
The Malloc appears to be the active in-use tiles, and there is a hard cap on how many can be allocated. In my app that number is 16, not sure if its based on UIView size or not. These allocations seem to be stringently managed, and it responds to memory warnings.
Anyway, at a certain zoom level, say, continent level (enough to fit most of North America in an iPad screen), given the size of the tiles, if never really has to get to that second level of caching (NSData (Store)) in order to complete the map. Everything is crisp and clean. If I load in a ton of external images into active memory, the tiles prune themselves. Awesome!
The problem comes when it hits that second level of caching. This happens when you zoom in, and suddenly instead of 16 tiles to show the entire planat, it needs 16 tiles just to show off Los Angelas, and as you pan around instead of just dumping those old tiles it puts them into the NSData (store) allocations where they seem to never get freed.
This NSData (store) is the NSURLConnectionCache which exists by default only in memory. You can't access this cache to limit it, because it's not the default shared cache (already tried it).
So this is where I get stuck.
The unsatisfying answer is that if you disable map zooming and fix it at a reasonably broad zoom level, you can avoid this problem completely, but obviously some apps need this... and that's as far as I got.
I filed a support ticket with Apple to see if they can divulge any way to limit this ridiculous cache for the map (which by the way I was able to casually crank up to 50+ megs of RAM allocated in active memory).
Hope this helps.
edit
The next iOS release appears to have solved this limitless cache issue. MKMapView now aggressively prunes its cached tile data. REJOICE!
Are you setting the reuse identifier on your annotation views? (This means the system can detach those views and only keep a small number of views in memory at once. It also increases scrolling performance, because scrolling will reuse the detached views.)
Use this method to get an annotation view to be reused:
- (MKAnnotationView *)dequeueReusableAnnotationViewWithIdentifier:(NSString *)identifier
If you create an app with just the mapkit and a view size of 768x1024 (ipad size), the app can easily consume over 30+ MB of "Live Bytes" as reported by Instruments Allocations program. This was noticed running on the iPad iOS v3.2.2 (the latest version until next weeks supposed 4.2 release). From my research it seems that this amount of memory is a lot for a single app, where most developers report receiving a level 1 memory warning around 15-25 MB and crashes soon after that level.