I'm getting memory leak with UIImagePickerController class.
Here's how I'm using it:
UIImagePickerController *picker = [[UIImagePickerController alloc] init];
picker.delegate = self;
picker.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
[self presentModalViewController:picker animated:YES];
[picker release];
To remove the picker i call [picker dismissModalViewControllerAnimated:YES]; in didFinishPickingImage and imagePickerControllerDidCancel.
--
Instruments show around 160bytes leaking as a result of this instruction:
+[UIImagePickerController _loadPhotoLibraryIfNecessary]
Apparently this issue has and is disturbing many people, and solution
to avoid this problem is to build a
singleton class dedicated for picking
images from library or capturing using
device's build in camera.
Anyone want to add something?
As the author of one of the first articles about the necessity to use a singleton, the motivation was to prevent a crash on the 7/8th image capture, not because of any particular worry about the leak. 160 bytes is annoying, but not a major problem, and therefore not worth worrying about (because it can't be fixed by developers).
Have you tried deleting the delegate line? I’ve had similar problems with AVAudioPlayer when delegating to self. (Even though the accessor says assign in both cases.) If the leak goes away with the delegation, you can delegate to a different object.
I was having a memory alloc leak which I found in Instruments.
All I was doing was opening and closing the image picker (open/cancel) and using Apple code, my code and other people's code.
All were showing the allocation going up and up each time, as if the picker was not being released.
If you tried to release it, it would crash (over released).
Then I found a really helpful web page which basically stated:
"This doesn't happen when testing on the device"
So I switched from the simulator and ran the tests on the device.
Lo & behold there was no allocation increase and it behaved normally.
This however is totally evil and now we can place no trust in the simulator to do a reliable job. Whether this is pertinent to your specific problem or not, I took you up on anything else to add, and my thing to add is don't test memory on the simulator!
The reason maybe that you forget to release image. Because each time you write
UIImageView.image = image_a;
Then , image_a will get retained once.
Until you let UIImageView.image = nil, when image_a can be release finally.
I resolved my problem in this way.
If you see memory leaks several GeneralBlock and SegmentMachO by using UIImagePickerController,
Try by adding CoreLocation framework and MapKit framework to your project. I don't see anymore memory leaks in the instrument tool leak checking. I don't know how UIImagePickerController related to these frameworks. I am not sure it is good solution or not. "adding frameworks without using or necessary".
I have also got the memory leak by using UIImagePickerController. That memory leak happen even in the sample code "PhotoLocation" and "iPhoneCoreDataRecipes" downloaded from developer.apple.com. I also checked by adding these frameworks to those downloaded sample code. There is no memory leaks anymore.
Related
I am seeing a huge memory leak when using UIImagePickerController in my iPhone app. I am using standard code from the apple documents to implement the control:
UIImagePickerController* imagePickerController = [[UIImagePickerController alloc] init];
imagePickerController.delegate = self;
if ([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera]) {
switch (buttonIndex) {
case 0:
imagePickerController.sourceType = UIImagePickerControllerSourceTypeCamera;
[self presentModalViewController:imagePickerController animated:YES];
break;
case 1:
imagePickerController.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
[self presentModalViewController:imagePickerController animated:YES];
break;
default:
break;
}
}
And for the cancel:
-(void) imagePickerControllerDidCancel:(UIImagePickerController *)picker
{
[[picker parentViewController] dismissModalViewControllerAnimated: YES];
[picker release];
}
The didFinishPickingMediaWithInfo callback is just as stanard, although I do not even have to pick anything to cause the leak.
Here is what I see in instruments when all I do is open the UIImagePickerController, pick photo library, and press cancel, repeatedly. As you can see the memory keeps growing, and eventually this causes my iPhone app to slow down tremendously.
As you can see I opened the image picker 24 times, and each time it malloc'd 128kb which was never released. Basically 3mb out of my total 6mb is never released.
This memory stays leaked no matter what I do. Even after navigating away from the current controller, is remains the same. I have also implemented the picker control as a singleton with the same results.
Here is what I see when I drill down into those two lines:
Any help here would be greatly appreciated! Again, I do not even have to choose an image. All I do is present the controller, and press cancel.
Update 1
I downloaded and ran apple's example of using the UIIMagePickerController and I see the same leak happening there when running instruments (both in simulator and on the phone).
http://developer.apple.com/library/ios/#samplecode/PhotoPicker/Introduction/Intro.html%23//apple_ref/doc/uid/DTS40010196
All you have to do is hit the photo library button and hit cancel over and over, you'll see the memory keep growing.
Any ideas?
Update 2
I only see this problem when viewing the photo library. I can choose take photo, and open and close that one over and over, without a leak.
It's a bug in the SDK. File a report with Apple. I have the samme isue. It is also documented here: http://www.cocoabuilder.com/archive/cocoa/285293-iphone-memory-leak-can-explain.html
and that was over a year ago and still no fix.
A few of our apps reuse the same UIImagePickerController due to a leak in 2.x (it makes me feel old...). I was under the impression that the leak was fixed, but I could be wrong.
It's a slightly horrible workaround, but sometimes that's the best you can do.
Try setting the UIImagePickerController.delegate to nil before releasing.
-(void) imagePickerControllerDidCancel:(UIImagePickerController *)picker
{
[[picker parentViewController] dismissModalViewControllerAnimated: YES];
picker.delegate = nil;
[picker release];
}
The "Mark Heap" button in Instruments has been, for me, the absolute best way of tracking down these sorts of issues.
This is an OK article on how to use it: http://www.friday.com/bbum/2010/10/17/when-is-a-leak-not-a-leak-using-heapshot-analysis-to-find-undesirable-memory-growth/
But it will tell you, for sure, which objects are surviving longer than you expect... and, ultimately, what the source of the issue is.
You can also see a complete retain/release trace for each individual object which survived - allowing you to pinpoint where your problem is.
EDIT: I use a UIImagePickerControllers as well, and I can promise it doesn't leak (at lesat for me) the way you're suggesting - so, whatever is going on, it's almost surely fixable.
I used UIImagePickerController and after 40 capture images my application received a DidMemoryWarning message and stop, hidden all my views.
In my application I create 40 objects of
UIImagePickerController( new UIImagePickerController() )
To work correctly I create a unique instance shared to all application and with this all work correctly.
I supusose that control lost memory too, but only one time. My application can capture images from camera correctly:
private static UIImagePickerController picker = new UIImagePickerController();
Instruments show me a leak in simulator in the following code,
UIBarButtonItem *connectButton = [[UIBarButtonItem alloc] initWithTitle:#"Connexion" style:UIBarButtonItemStyleBordered target:self action:#selector(pushViewController)];
[self.navigationItem setLeftBarButtonItem:connectButton animated:animated];
[connectButton release];
Do you see any leak ?? thanks
Leaks is showing you where the object was allocated, not where the object was leaked.
While the two might be the same, it is often much more likely that the leak of an object is caused by an extra retain or missing release somewhere else.
I don't see any leaks in the code you posted. That said, a couple questions:
How do you know that's where the leak is?
Any chance the getter for navigationItem is using copy? If so, there could be a leak there.
...and on device? You should check this on device. There are very, very few situations where you'd want to use the simulator for this kind of testing. It's not representative of how the device itself behaves. I'd recommend you test this on a device, and then if you're still seeing it come back here.
Dear all, I have a navigation-based app with about 60 UIControllerViews, which is divided into 4 sections.
I have run with the following : 1. Build and analyse : bulid is successful with no complains. 2. Instruments allocation and leaks : no leaks.
However, the app crashed in iPhone or iPad but works fine in simulator. There is no crash reports but I do see LowMemory.log in the crashreporter folder.
I have upgraded my iphone and ipad to 4.2
Does anyone have ideas what could be wrong? I have been reading and troubleshooting for a week.
Is there a need to remove/release the UIControllerViews?
The app crashes simply by navigating between the views.
Thank you for any help.
My app has a root view called contentViewController and users can navigate to 4 quizzes from here.
This is the code I use to return to my root view.
- (void)goHome {
UIAlertView *alert = [[UIAlertView alloc]
initWithTitle: #"Warning"
message: #"Proceed?"
delegate: self
cancelButtonTitle:#"Yes"
otherButtonTitles:#"No",nil];
[alert show];
[alert release];
}
- (void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex {
[[self navigationController] setNavigationBarHidden:NO animated:YES];
if (buttonIndex == 0) {
NSArray * subviews = [self.view subviews];
[subviews makeObjectsPerformSelector:#selector(removeFromSuperview)];
self.view = nil;
if (self.contentViewController == nil)
{
ContentViewController *aViewController = [[ContentViewController alloc]
initWithNibName:#"ContentViewController" bundle:[NSBundle mainBundle]];
self.contentViewController = aViewController;
[aViewController release];
}
[self.navigationController pushViewController:self.contentViewController animated:YES];
}
else {
}
}
The simulator isn't going to give you any useful information about memory warnings—your app, running there, effectively has access to all the memory the system's willing to give it. The device is where you need to be testing for memory usage, and if you're getting warnings and crashes, then you need to do some Instruments work to figure out where you can free up some of that memory.
Look at your xcode console. If you are getting a number of low memory warnings, then you need to be allocating and de-allocating your views on the fly because they are taking up too much memory on the device (the simulator isn't quite so memory restricted).
But it could be about a million other things causing your crash. Make sure you're doing a debug build (breakpoints on) so the debugger will kick in and hopefully you can see where on the stack your crash is occurring.
You have some good suggestions already. However I'd suggest spending a lot of time reviewing XCode's debugging tools documentation. This so you have a basic understanding of what they are capable of and how to use them. Follow that up with some reading on iOS memory management, auto release pools and the like.
For your app you need to realize that there is no swap space on iOS devices. So you are forced to manage memory to an extent that you mat not have to on other platforms. Generally that means you don't want to keep to much view data in memory if it can be avoided.
In the case of the current iPad there may only be about 110MB of RAM available to the app. Specific numbers probably are iOS version dependent. In any event you need to get an idea as to how large the data structures (in memory) are for your various views. 60 different views could be considered a lot depending upon memory usage, if you don't manage it correctly you are likely to run out very quickly. This not like programming in Java or other garbage collected language.
Lastly; even though this sounds like a memory management issue it could always be something else. If you still have trouble you will need to post code. Right now it is really guess work on our part. Just remember you do not have VM and there is no garbage collection.
You are using up memory, always remember if you allocate memory you must release it, in some cases you can use autorelease so you dont forget to release it after the void dealloc method before end.
I'm experiencing a wierd behavior in the new AVFoundation classes in the iPhone SDK.
I have a AVCaptureStillImageOutput for taking pictures, and I am setting its outputSettings to my liking. The code follows:
AVCaptureStillImageOutput *stillImageOutput = [[[AVCaptureStillImageOutput alloc] init] autorelease];
[stillImageOutput setOutputSettings:[NSDictionary dictionaryWithObject:AVVideoCodecJPEG forKey:AVVideoCodecKey]];
[self setStillImageOutput:stillImageOutput];
(stillImageOutput property is defined as "retain")
I stumbled upon a leak in leaks, with 100% of the leak fault on the setOutputSettings line. I believe that I confine to the memory management guidelines in the code attached, still it is leaking.
My solution was to
[self.stillImageOutput setOutputSettings:nil];
in the dealloc, just before
[self setStillImageOutput:nil];
The leak indeed stopped, but it looks weird. Shouldn't the releasing of stillImageOutput release its outputSettings property as well?
Anyway, if someone else runs into this, thought I should share my solution.
Cheers!
Oded.
Yes, the releasing of stillImageOutput should release it's outputSettings property as well. Either it's an Apple bug (should let them know, your use case is pretty simple) or remove your line, and see whether anything other than your class is hanging onto that stillImageOutput object (which is holding the outputSettings).
This is driving me crazy!!!
I'm getting a "Received memory warning. Level=1" whenever I attempt to show a UIImagePickerController with a sourceType = UIImagePickerControllerSourceTypeCamera.
Here is the code from my viewDidLoad where I set things up:
- (void)viewDidLoad {
[super viewDidLoad];
// Set card table green felt background
self.view.backgroundColor = [UIColor colorWithPatternImage: [UIImage imageNamed:#"green_felt_bg.jpg"]];
// Init UIImagePickerController
// Instantiate a UIImagePickerController for use throughout app and set delegate
self.playerImagePicker = [[UIImagePickerController alloc] init];
self.playerImagePicker.delegate = self;
self.playerImagePicker.sourceType = UIImagePickerControllerSourceTypeCamera;
}
And here is how I present it modally ..
- (IBAction) addPlayers: (id)sender{
[self presentModalViewController:self.playerImagePicker animated:YES];
}
The result ... UIImagePicker starts to show and then boom ... I get the memory warning ... EVERY TIME! Interestingly enough, if I switch to sourceType = UIImagePickerControllerSourceTypePhotoLibrary ... everything works fine.
What in the heck am I missing or doing wrong? All I want to do is show the camera, take and save a picture.
FYI - I'm testing on my 3GS device.
Thanks to anyone who can help :)
This is very common. As long as you handle the memory warning without crashing and have enough space to keep going, don't let it drive you crazy.
It is not about how much memory your app has used, because it will probably happen even when you write a very simple app which have only one view with one button, clicking the button and then open camera.
I have tested on iPhone 3GS, iPad 2 and iPod touch 3G. It only happened in iPhone 3GS.
I found it will not happen anymore if you restart you device before you execute you app.
Another real solution is to comment the code, [super didReceiveMemoryWarning], in your viewController.
- (void)didReceiveMemoryWarning
{
// Releases the view if it doesn't have a superview.
[super didReceiveMemoryWarning];
// Release any cached data, images, etc that aren't in use.
}
After lots of test on iPhone 3GS with iOS 4.3.2, I found the logic might like that:
-> Open as much as app running on background
-> Presenting a imagePicker of UIImagePickerController, clicking "Back" or "Save" from imagePicker
-> ApplicationDelegate's method, applicationDidReceiveMemoryWarning:(UIApplication *)application, will be invoked
-> Then ViewController's method, didReceiveMemoryWarning:, will be invoked
-> Then viewDidUnload
-> Then viewDidLoad
Then you could find some views have been released and the current view has been pointed to a unexpected one.
By default, [super didReceiveMemoryWarning] will run when ViewController's didReceiveMemoryWarning method is invoked. Commenting it, and viewDidUnload: and viewDidLoad: methods will not be invoked. It means the mem warning has been totally ignored. That's what we expected.
Now after I upgraded to 4.0 it happens to my app too - before in 3.1 there were no warnings.
Actually as you said before, there should be no issue. However, this causes the view that comes after it to load again and viewDidLoad is being called. This messes up my app, since I initialize the view in viewDidLoad - now it gets initialized all over again - even though it shouldn't.
Just as a comment, this might also happen to many other apps that rely on loading the view only once!
It did happen in my app Did I Do That on iOS 4.0 too. It was not consistent, but the most common cause was creating a UIImagePickerController instance and navigating to some large photo stored in one of the albums.
Fixed by persisting state in the didReceiveMemoryWarning method, and loading from state in the viewDidLoad method. One caveat is to remember to clear the state-persisted file in the correct point for your application. For me it was leaving the relevant UIViewController under normal circumstances.
I'm getting the memory warning when opening a UIImagePickerController as well. I'm on 4.01 as well.
But in addition, the UIImagePickerController is running the close shutter animation and stalling there, with the closed shutter on screen.
It seems like the UIImagePickerController's behavior on memory warnings is to close itself.
I could dismiss the UIImagePickerController from the parent ViewController in the didReceiveMemoryWarning method, but that would make for a terrible user experience.
Has anyone seen this problem?
Is there a way to handle the memory warning so that the UIImagePickerController doesn't shut itself down?
I have been struggling with the same problem for some days now. However, resetting my iPhone 4 (clearing out memory) solves the problem so it's not really an app problem.
It appears that a level 1 or 2 memory warning triggers the UIimgPickerController delegate to offload itself. The same happens in my app with the delegate of the delegate (yes it can). After the memory warning however, it will load the delegate (and it's delegate) again causing the viewDidLoad to execute any code that's in there.
I am not sure this happens only while using the UIimgPickerController because testing all that is very time consuming.
I could write some extra code to prevent the code in viewDidLoad en viewWillAppear from execuring while showing the UIimgPickerController but that's not classy, right?
Here's food for thought: it could be
that you are running out of memory
because you are testing your app. With
some memoryleaks it is very well
possible that you are working towards
this problem every time you debug.
The UIImagePickerControllerDelegate is a memory hog because you are capturing high memory assets, be that an image or video. So from the start be sure to specify the medium capture settings, as a start point, reduce this if you don't need the quality:
UIImagePickerController *picker = [[UIImagePickerController alloc] init];
picker.delegate = self;
picker.videoQuality=UIImagePickerControllerQualityTypeMedium;
Then after capturing and using these assets. Remove any temp files from the applications temp folder. Could be an extra obsessive step but its a good habit:
NSFileManager *fileManager = [NSFileManager defaultManager];
if ([fileManager fileExistsAtPath:[lastCapturedFile substringFromIndex:7] ]) {
NSError *error;
// Attempt to delete the folder containing globalDel.videoPath
if ([fileManager removeItemAtPath:[lastCapturedFile substringFromIndex:7] error:&error] != YES) {
NSLog(#"Unable to delete recorded file: %#", [error localizedDescription]);
} else {
NSLog(#"deleted file");
}
}
With above it is clearing the file that was created by the delegate. In some instances if you are transcoding or creating you own assets delete the folder with that file. Note above I am removing the 'file://' part of the url string as the file manager doesn't like it:
[lastCapturedFile substringFromIndex:7]
Other things to consider are covered in the various documentation for what you are doing with that asset - transcoding, image size reduction and more. Beware that any transcoding using the AVFoundation will crash if the UIImagePickerViewController is displaying.